ncca-ngl 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. ncca_ngl-0.1.0/LICENSE.txt +7 -0
  2. ncca_ngl-0.1.0/PKG-INFO +23 -0
  3. ncca_ngl-0.1.0/README.md +22 -0
  4. ncca_ngl-0.1.0/pyproject.toml +47 -0
  5. ncca_ngl-0.1.0/setup.cfg +4 -0
  6. ncca_ngl-0.1.0/src/ncca/ngl/PrimData/pack_arrays.py +20 -0
  7. ncca_ngl-0.1.0/src/ncca/ngl/__init__.py +100 -0
  8. ncca_ngl-0.1.0/src/ncca/ngl/abstract_vao.py +89 -0
  9. ncca_ngl-0.1.0/src/ncca/ngl/base_mesh.py +170 -0
  10. ncca_ngl-0.1.0/src/ncca/ngl/base_mesh.pyi +11 -0
  11. ncca_ngl-0.1.0/src/ncca/ngl/bbox.py +224 -0
  12. ncca_ngl-0.1.0/src/ncca/ngl/bezier_curve.py +75 -0
  13. ncca_ngl-0.1.0/src/ncca/ngl/first_person_camera.py +174 -0
  14. ncca_ngl-0.1.0/src/ncca/ngl/image.py +94 -0
  15. ncca_ngl-0.1.0/src/ncca/ngl/log.py +44 -0
  16. ncca_ngl-0.1.0/src/ncca/ngl/mat2.py +128 -0
  17. ncca_ngl-0.1.0/src/ncca/ngl/mat3.py +466 -0
  18. ncca_ngl-0.1.0/src/ncca/ngl/mat4.py +456 -0
  19. ncca_ngl-0.1.0/src/ncca/ngl/multi_buffer_vao.py +49 -0
  20. ncca_ngl-0.1.0/src/ncca/ngl/obj.py +416 -0
  21. ncca_ngl-0.1.0/src/ncca/ngl/plane.py +47 -0
  22. ncca_ngl-0.1.0/src/ncca/ngl/primitives.py +706 -0
  23. ncca_ngl-0.1.0/src/ncca/ngl/pyside_event_handling_mixin.py +318 -0
  24. ncca_ngl-0.1.0/src/ncca/ngl/quaternion.py +112 -0
  25. ncca_ngl-0.1.0/src/ncca/ngl/random.py +167 -0
  26. ncca_ngl-0.1.0/src/ncca/ngl/shader.py +229 -0
  27. ncca_ngl-0.1.0/src/ncca/ngl/shader_lib.py +536 -0
  28. ncca_ngl-0.1.0/src/ncca/ngl/shader_program.py +816 -0
  29. ncca_ngl-0.1.0/src/ncca/ngl/simple_index_vao.py +65 -0
  30. ncca_ngl-0.1.0/src/ncca/ngl/simple_vao.py +42 -0
  31. ncca_ngl-0.1.0/src/ncca/ngl/text.py +346 -0
  32. ncca_ngl-0.1.0/src/ncca/ngl/texture.py +75 -0
  33. ncca_ngl-0.1.0/src/ncca/ngl/transform.py +95 -0
  34. ncca_ngl-0.1.0/src/ncca/ngl/util.py +128 -0
  35. ncca_ngl-0.1.0/src/ncca/ngl/vao_factory.py +34 -0
  36. ncca_ngl-0.1.0/src/ncca/ngl/vec2.py +350 -0
  37. ncca_ngl-0.1.0/src/ncca/ngl/vec2_array.py +106 -0
  38. ncca_ngl-0.1.0/src/ncca/ngl/vec3.py +401 -0
  39. ncca_ngl-0.1.0/src/ncca/ngl/vec3_array.py +110 -0
  40. ncca_ngl-0.1.0/src/ncca/ngl/vec4.py +229 -0
  41. ncca_ngl-0.1.0/src/ncca/ngl/vec4_array.py +106 -0
  42. ncca_ngl-0.1.0/src/ncca_ngl.egg-info/PKG-INFO +23 -0
  43. ncca_ngl-0.1.0/src/ncca_ngl.egg-info/SOURCES.txt +71 -0
  44. ncca_ngl-0.1.0/src/ncca_ngl.egg-info/dependency_links.txt +1 -0
  45. ncca_ngl-0.1.0/src/ncca_ngl.egg-info/requires.txt +6 -0
  46. ncca_ngl-0.1.0/src/ncca_ngl.egg-info/top_level.txt +1 -0
  47. ncca_ngl-0.1.0/tests/test_base_mesh.py +249 -0
  48. ncca_ngl-0.1.0/tests/test_bbox.py +153 -0
  49. ncca_ngl-0.1.0/tests/test_bezier_curve.py +78 -0
  50. ncca_ngl-0.1.0/tests/test_first_person_camera.py +98 -0
  51. ncca_ngl-0.1.0/tests/test_image.py +66 -0
  52. ncca_ngl-0.1.0/tests/test_logging.py +9 -0
  53. ncca_ngl-0.1.0/tests/test_mat2.py +70 -0
  54. ncca_ngl-0.1.0/tests/test_mat3.py +241 -0
  55. ncca_ngl-0.1.0/tests/test_mat4.py +287 -0
  56. ncca_ngl-0.1.0/tests/test_obj.py +313 -0
  57. ncca_ngl-0.1.0/tests/test_plane.py +74 -0
  58. ncca_ngl-0.1.0/tests/test_primitives.py +121 -0
  59. ncca_ngl-0.1.0/tests/test_pyside_event_handling_mixin.py +644 -0
  60. ncca_ngl-0.1.0/tests/test_quaternion.py +133 -0
  61. ncca_ngl-0.1.0/tests/test_random.py +130 -0
  62. ncca_ngl-0.1.0/tests/test_shaderlib.py +1207 -0
  63. ncca_ngl-0.1.0/tests/test_text.py +15 -0
  64. ncca_ngl-0.1.0/tests/test_texture.py +75 -0
  65. ncca_ngl-0.1.0/tests/test_transform.py +160 -0
  66. ncca_ngl-0.1.0/tests/test_util.py +103 -0
  67. ncca_ngl-0.1.0/tests/test_vao.py +150 -0
  68. ncca_ngl-0.1.0/tests/test_vec2.py +216 -0
  69. ncca_ngl-0.1.0/tests/test_vec2_array.py +112 -0
  70. ncca_ngl-0.1.0/tests/test_vec3.py +324 -0
  71. ncca_ngl-0.1.0/tests/test_vec3_array.py +112 -0
  72. ncca_ngl-0.1.0/tests/test_vec4.py +281 -0
  73. ncca_ngl-0.1.0/tests/test_vec4_array.py +112 -0
@@ -0,0 +1,7 @@
1
+ Copyright 2024 Jon Macey
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: ncca-ngl
3
+ Version: 0.1.0
4
+ Summary: A Python version of the NGL graphics library.
5
+ Author-email: Jon Macey <jmacey@bournemouth.ac.uk>
6
+ License: Copyright 2024 Jon Macey
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ Project-URL: Homepage, https://github.com/NCCA/PyNGL
14
+ Project-URL: Issues, https://github.com/NCCA/PyNGL/issues
15
+ Requires-Python: >=3.13
16
+ License-File: LICENSE.txt
17
+ Requires-Dist: numpy>=2.3.3
18
+ Requires-Dist: PyOpenGL
19
+ Requires-Dist: Pillow
20
+ Requires-Dist: glfw>=2.9.0
21
+ Requires-Dist: freetype-py>=2.5.1
22
+ Requires-Dist: pyside6>=6.9.2
23
+ Dynamic: license-file
@@ -0,0 +1,22 @@
1
+ # PyNGL
2
+
3
+ This is the code for the full python version of [NGL](https://github.com/NCCA/NGL) the ncca graphics library.
4
+
5
+ More details soon as this is work in progress.
6
+
7
+
8
+ ## Test
9
+
10
+ use
11
+
12
+ ```
13
+ uv run pytest
14
+ ```
15
+
16
+ To run tests,
17
+
18
+ ```
19
+ uv run pytest --cov=src --cov-report=term-missing
20
+ ```
21
+
22
+ For coverage reports.
@@ -0,0 +1,47 @@
1
+ [project]
2
+ name = "ncca-ngl"
3
+ version = "0.1.0"
4
+ description = "A Python version of the NGL graphics library."
5
+ authors = [{ name = "Jon Macey", email = "jmacey@bournemouth.ac.uk" }]
6
+ requires-python = ">=3.13"
7
+ license = { file = "LICENSE.txt" }
8
+
9
+ dependencies = [
10
+ "numpy>=2.3.3",
11
+ "PyOpenGL",
12
+ "Pillow",
13
+ "glfw>=2.9.0",
14
+ "freetype-py>=2.5.1",
15
+ "pyside6>=6.9.2",
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/NCCA/PyNGL"
20
+ Issues = "https://github.com/NCCA/PyNGL/issues"
21
+
22
+ [tool.setuptools.packages.find]
23
+ where = ["src"]
24
+ include = ["ncca.*"]
25
+
26
+ [tool.pytest.ini_options]
27
+ pythonpath = ["src","tests"]
28
+
29
+ # [build-system]
30
+ # requires = ["uv_build>=0.8.14,<0.9.0"]
31
+ # build-backend = "uv_build"
32
+ # module-name = ["ncca.ngl"]
33
+ # module-root = "src/ncca/"
34
+
35
+ [build-system]
36
+ requires = ["setuptools>=61.0"]
37
+ build-backend = "setuptools.build_meta"
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "coverage>=7.10.6",
42
+ "pytest>=8.4.2",
43
+ "pytest-cov>=7.0.0",
44
+ "ruff>=0.13.0",
45
+ "pre-commit>=4.3.0",
46
+
47
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import numpy as np
4
+ import pathlib
5
+
6
+ files = pathlib.Path(".").glob("*.npy")
7
+
8
+ data = {}
9
+ for f in files:
10
+ data[str(f.stem)] = np.load(f)
11
+ # arrays.append(np.load(f))
12
+ # names.append(str(f.stem))
13
+ print(data.keys())
14
+
15
+
16
+ np.savez_compressed("Primitives", **data)
17
+
18
+ loaded = np.load("Primitives.npz")
19
+ print(loaded)
20
+ print(loaded["dragon"])
@@ -0,0 +1,100 @@
1
+ from .abstract_vao import AbstractVAO, VertexData
2
+ from .base_mesh import BaseMesh, Face
3
+ from .bbox import BBox
4
+ from .bezier_curve import BezierCurve
5
+ from .first_person_camera import FirstPersonCamera
6
+ from .image import Image, ImageModes
7
+ from .log import logger
8
+ from .mat2 import Mat2
9
+ from .mat3 import Mat3, Mat3Error, Mat3NotSquare
10
+ from .mat4 import Mat4, Mat4Error, Mat4NotSquare
11
+ from .multi_buffer_vao import MultiBufferVAO
12
+ from .obj import (
13
+ Obj,
14
+ ObjParseFaceError,
15
+ ObjParseNormalError,
16
+ ObjParseUVError,
17
+ ObjParseVertexError,
18
+ )
19
+ from .plane import Plane
20
+ from .primitives import Primitives, Prims
21
+ from .pyside_event_handling_mixin import PySideEventHandlingMixin
22
+ from .quaternion import Quaternion
23
+ from .random import Random
24
+ from .shader import MatrixTranspose, Shader, ShaderType
25
+ from .shader_lib import DefaultShader, ShaderLib
26
+ from .shader_program import ShaderProgram
27
+ from .simple_index_vao import IndexVertexData, SimpleIndexVAO
28
+ from .simple_vao import SimpleVAO
29
+ from .text import Text
30
+ from .texture import Texture
31
+ from .transform import Transform, TransformRotationOrder
32
+ from .util import calc_normal, clamp, frustum, lerp, look_at, ortho, perspective
33
+ from .vao_factory import VAOFactory, VAOType
34
+ from .vec2 import Vec2
35
+ from .vec2_array import Vec2Array
36
+ from .vec3 import Vec3
37
+ from .vec3_array import Vec3Array
38
+ from .vec4 import Vec4
39
+ from .vec4_array import Vec4Array
40
+
41
+ all = [
42
+ AbstractVAO,
43
+ VertexData,
44
+ BaseMesh,
45
+ Face,
46
+ BBox,
47
+ BezierCurve,
48
+ Image,
49
+ ImageModes,
50
+ Mat2,
51
+ Mat3,
52
+ Mat4,
53
+ MultiBufferVAO,
54
+ Obj,
55
+ Plane,
56
+ Quaternion,
57
+ MatrixTranspose,
58
+ Shader,
59
+ ShaderProgram,
60
+ ShaderType,
61
+ ShaderLib,
62
+ IndexVertexData,
63
+ SimpleIndexVAO,
64
+ SimpleVAO,
65
+ Texture,
66
+ VAOFactory,
67
+ Vec2,
68
+ Vec3,
69
+ Vec4,
70
+ Vec3Array,
71
+ Vec2Array,
72
+ Vec4Array,
73
+ ObjParseVertexError,
74
+ ObjParseNormalError,
75
+ ObjParseUVError,
76
+ ObjParseFaceError,
77
+ clamp,
78
+ lerp,
79
+ look_at,
80
+ perspective,
81
+ ortho,
82
+ frustum,
83
+ Transform,
84
+ TransformRotationOrder,
85
+ Random,
86
+ Text,
87
+ calc_normal,
88
+ Mat3Error,
89
+ Mat4Error,
90
+ Mat3NotSquare,
91
+ Mat4NotSquare,
92
+ Mat4NotSquare,
93
+ VAOType,
94
+ DefaultShader,
95
+ logger,
96
+ Primitives,
97
+ Prims,
98
+ FirstPersonCamera,
99
+ PySideEventHandlingMixin,
100
+ ]
@@ -0,0 +1,89 @@
1
+ import abc
2
+ import ctypes
3
+
4
+ import numpy as np
5
+ import OpenGL.GL as gl
6
+
7
+ from .log import logger
8
+
9
+
10
+ class VertexData:
11
+ def __init__(self, data, size, mode=gl.GL_STATIC_DRAW):
12
+ if isinstance(data, np.ndarray):
13
+ self.data = data
14
+ else:
15
+ self.data = np.array(data, dtype=np.float32)
16
+ self.size = size
17
+ self.mode = mode
18
+
19
+
20
+ class AbstractVAO(abc.ABC):
21
+ def __init__(self, mode=gl.GL_TRIANGLES):
22
+ self.id = gl.glGenVertexArrays(1)
23
+ self.mode = mode
24
+ self.bound = False
25
+ self.allocated = False
26
+ self.indices_count = 0
27
+
28
+ def bind(self):
29
+ gl.glBindVertexArray(self.id)
30
+ self.bound = True
31
+
32
+ def unbind(self):
33
+ gl.glBindVertexArray(0)
34
+ self.bound = False
35
+
36
+ def __enter__(self):
37
+ self.bind()
38
+ return self
39
+
40
+ def __exit__(self, exc_type, exc_val, exc_tb):
41
+ self.unbind()
42
+
43
+ @abc.abstractmethod
44
+ def draw(self):
45
+ raise NotImplementedError
46
+
47
+ @abc.abstractmethod
48
+ def set_data(self, data):
49
+ raise NotImplementedError
50
+
51
+ @abc.abstractmethod
52
+ def remove_vao(self):
53
+ raise NotImplementedError
54
+
55
+ def set_vertex_attribute_pointer(
56
+ self, id, size, type, stride, offset, normalize=False
57
+ ):
58
+ if not self.bound:
59
+ logger.error("VAO not bound in set_vertex_attribute_pointer")
60
+ gl.glVertexAttribPointer(
61
+ id, size, type, normalize, stride, ctypes.c_void_p(offset)
62
+ )
63
+ gl.glEnableVertexAttribArray(id)
64
+
65
+ def set_num_indices(self, count):
66
+ self.indices_count = count
67
+
68
+ def num_indices(self):
69
+ return self.indices_count
70
+
71
+ def get_mode(self):
72
+ return self.mode
73
+
74
+ def set_mode(self, mode):
75
+ self.mode = mode
76
+
77
+ @abc.abstractmethod
78
+ def get_buffer_id(self, index=0):
79
+ raise NotImplementedError
80
+
81
+ @abc.abstractmethod
82
+ def map_buffer(self, index=0, access_mode=gl.GL_READ_WRITE):
83
+ raise NotImplementedError
84
+
85
+ def unmap_buffer(self):
86
+ gl.glUnmapBuffer(gl.GL_ARRAY_BUFFER)
87
+
88
+ def get_id(self):
89
+ return self.id
@@ -0,0 +1,170 @@
1
+ from dataclasses import dataclass
2
+
3
+ import numpy as np
4
+ import OpenGL.GL as gl
5
+
6
+ from . import vao_factory
7
+ from .abstract_vao import VertexData
8
+ from .bbox import BBox
9
+ from .log import logger
10
+
11
+
12
+ class Face:
13
+ """
14
+ Simple face structure for mesh geometry.
15
+ Holds indices for vertices, UVs, and normals.
16
+ """
17
+
18
+ slots = ("vertex", "uv", "normal")
19
+
20
+ def __init__(self):
21
+ self.vertex: list[int] = []
22
+ self.uv: list[int] = []
23
+ self.normal: list[int] = []
24
+
25
+
26
+ class BaseMesh:
27
+ """
28
+ Base class for mesh geometry.
29
+ Provides storage for vertices, normals, UVs, faces, and VAO management.
30
+ """
31
+
32
+ def __init__(self):
33
+ self.vertex: list = []
34
+ self.normals: list = []
35
+ self.uv: list = []
36
+ self.faces: list[Face] = []
37
+ self.vao = None
38
+ self.bbox = None
39
+ self.min_x: float = 0.0
40
+ self.max_x: float = 0.0
41
+ self.min_y: float = 0.0
42
+ self.max_y: float = 0.0
43
+ self.min_z: float = 0.0
44
+ self.max_z: float = 0.0
45
+ self.texture_id: int = 0
46
+ self.texture: bool = False
47
+
48
+ def is_triangular(self) -> bool:
49
+ """
50
+ Check if all faces in the mesh are triangles.
51
+
52
+ Returns:
53
+ bool: True if all faces are triangles, False otherwise.
54
+ """
55
+ return all(len(f.vertex) == 3 for f in self.faces)
56
+
57
+ def create_vao(self, reset_vao: bool = False) -> None:
58
+ """
59
+ Create a Vertex Array Object (VAO) for the mesh.
60
+ Only supports triangular meshes.
61
+
62
+ Args:
63
+ reset_vao: If True, will not create a new VAO if one already exists.
64
+ Raises:
65
+ RuntimeError: If the mesh is not composed entirely of triangles.
66
+ """
67
+ if reset_vao:
68
+ if self.vao is not None:
69
+ logger.warning("VAO exist so returning")
70
+ return
71
+ else:
72
+ if self.vao is not None:
73
+ logger.warning("Creating new VAO")
74
+
75
+ data_pack_type = 0
76
+ if self.is_triangular():
77
+ data_pack_type = gl.GL_TRIANGLES
78
+ if data_pack_type == 0:
79
+ logger.error("Can only create VBO from all Triangle data at present")
80
+ raise RuntimeError("Can only create VBO from all Triangle data at present")
81
+
82
+ @dataclass
83
+ class VertData:
84
+ """
85
+ Structure for a single vertex's data, including position, normal, and UV.
86
+ """
87
+
88
+ x: float = 0.0
89
+ y: float = 0.0
90
+ z: float = 0.0
91
+ nx: float = 0.0
92
+ ny: float = 0.0
93
+ nz: float = 0.0
94
+ u: float = 0.0
95
+ v: float = 0.0
96
+
97
+ def as_array(self) -> np.ndarray:
98
+ return np.array(
99
+ [self.x, self.y, self.z, self.nx, self.ny, self.nz, self.u, self.v],
100
+ dtype=np.float32,
101
+ )
102
+
103
+ vbo_mesh: list[VertData] = []
104
+ for face in self.faces:
105
+ for i in range(3):
106
+ d = VertData()
107
+ d.x = self.vertex[face.vertex[i]].x
108
+ d.y = self.vertex[face.vertex[i]].y
109
+ d.z = self.vertex[face.vertex[i]].z
110
+ if self.normals and self.uv:
111
+ d.nx = self.normals[face.normal[i]].x
112
+ d.ny = self.normals[face.normal[i]].y
113
+ d.nz = self.normals[face.normal[i]].z
114
+ d.u = self.uv[face.uv[i]].x
115
+ d.v = 1 - self.uv[face.uv[i]].y # Flip V for OpenGL
116
+ elif self.normals and not self.uv:
117
+ d.nx = self.normals[face.normal[i]].x
118
+ d.ny = self.normals[face.normal[i]].y
119
+ d.nz = self.normals[face.normal[i]].z
120
+ elif not self.normals and self.uv:
121
+ d.u = self.uv[face.uv[i]].x
122
+ d.v = 1 - self.uv[face.uv[i]].y
123
+ vbo_mesh.append(d)
124
+
125
+ mesh_data = np.concatenate([v.as_array() for v in vbo_mesh]).astype(np.float32)
126
+ self.vao = vao_factory.VAOFactory.create_vao(
127
+ vao_factory.VAOType.SIMPLE, data_pack_type
128
+ )
129
+ with self.vao as vao:
130
+ mesh_size = len(mesh_data) // 8
131
+ vao.set_data(VertexData(mesh_data, mesh_size))
132
+ # vertex
133
+ vao.set_vertex_attribute_pointer(0, 3, gl.GL_FLOAT, 8 * 4, 0)
134
+ # normals
135
+ vao.set_vertex_attribute_pointer(1, 3, gl.GL_FLOAT, 8 * 4, 3 * 4)
136
+ # uvs
137
+ vao.set_vertex_attribute_pointer(2, 2, gl.GL_FLOAT, 8 * 4, 6 * 4)
138
+ vao.set_num_indices(mesh_size)
139
+ self.calc_dimensions()
140
+ self.bbox = BBox.from_extents(
141
+ self.min_x, self.max_x, self.min_y, self.max_y, self.min_z, self.max_z
142
+ )
143
+
144
+ def calc_dimensions(self) -> None:
145
+ """
146
+ Calculate the bounding box extents for the mesh.
147
+ Updates min_x, max_x, min_y, max_y, min_z, max_z.
148
+ """
149
+ if not self.vertex:
150
+ return
151
+ self.min_x = self.max_x = self.vertex[0].x
152
+ self.min_y = self.max_y = self.vertex[0].y
153
+ self.min_z = self.max_z = self.vertex[0].z
154
+ for v in self.vertex:
155
+ self.min_x = min(self.min_x, v.x)
156
+ self.max_x = max(self.max_x, v.x)
157
+ self.min_y = min(self.min_y, v.y)
158
+ self.max_y = max(self.max_y, v.y)
159
+ self.min_z = min(self.min_z, v.z)
160
+ self.max_z = max(self.max_z, v.z)
161
+
162
+ def draw(self) -> None:
163
+ """
164
+ Draw the mesh using its VAO and bound texture (if any).
165
+ """
166
+ if self.vao:
167
+ if self.texture_id:
168
+ gl.glBindTexture(gl.GL_TEXTURE_2D, self.texture_id)
169
+ with self.vao as vao:
170
+ vao.draw()
@@ -0,0 +1,11 @@
1
+ class Face:
2
+ vert: list
3
+ uv: list
4
+ normal: list
5
+
6
+ class BaseMesh:
7
+ verts: list
8
+ normals: list
9
+ uv: list
10
+ faces: list
11
+ def __init__(self) -> None: ...