e2D 2.0.0__cp313-cp313-win_amd64.whl → 2.0.2__cp313-cp313-win_amd64.whl
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.
- e2D/__init__.py +199 -72
- e2D/__init__.pyi +145 -0
- e2D/ccolors.c +34514 -0
- e2D/ccolors.cp313-win_amd64.pyd +0 -0
- e2D/ccolors.pyi +51 -0
- e2D/ccolors.pyx +350 -0
- e2D/color_defs.py +238 -0
- e2D/colors.py +380 -0
- e2D/colors.pyi +104 -0
- e2D/commons.py +38 -10
- e2D/commons.pyi +79 -0
- e2D/cvectors.c +152 -152
- e2D/cvectors.cp313-win_amd64.pyd +0 -0
- e2D/cvectors.pyi +243 -0
- e2D/devices.py +19 -6
- e2D/devices.pyi +65 -0
- e2D/plots.py +55 -29
- e2D/plots.pyi +238 -0
- e2D/shapes.py +81 -44
- e2D/shapes.pyi +272 -0
- e2D/test_colors.py +122 -0
- e2D/text_renderer.py +46 -16
- e2D/text_renderer.pyi +118 -0
- e2D/types.py +58 -0
- e2D/types.pyi +61 -0
- e2D/vectors.py +153 -61
- e2D/vectors.pyi +106 -0
- e2D/winrec.py +275 -0
- e2D/winrec.pyi +87 -0
- {e2d-2.0.0.dist-info → e2d-2.0.2.dist-info}/METADATA +95 -26
- e2d-2.0.2.dist-info/RECORD +46 -0
- {e2d-2.0.0.dist-info → e2d-2.0.2.dist-info}/WHEEL +1 -1
- e2d-2.0.0.dist-info/RECORD +0 -26
- {e2d-2.0.0.dist-info → e2d-2.0.2.dist-info}/licenses/LICENSE +0 -0
- {e2d-2.0.0.dist-info → e2d-2.0.2.dist-info}/top_level.txt +0 -0
e2D/__init__.py
CHANGED
|
@@ -6,9 +6,9 @@ Copyright (c) 2025 Riccardo Mariani
|
|
|
6
6
|
MIT License
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
__version__ = "2.0.
|
|
9
|
+
__version__ = "2.0.2"
|
|
10
10
|
__author__ = "Riccardo Mariani"
|
|
11
|
-
__email__ = "
|
|
11
|
+
__email__ = "riccardo.mariani@emptyhead.dev"
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
14
|
import moderngl
|
|
@@ -16,6 +16,12 @@ import glfw
|
|
|
16
16
|
import time
|
|
17
17
|
import os
|
|
18
18
|
|
|
19
|
+
# Import type definitions
|
|
20
|
+
from .types import (
|
|
21
|
+
ComputeShaderType, ProgramAttrType, UniformType, VectorType, ColorType, Number,
|
|
22
|
+
ContextType, ProgramType, BufferType, WindowType, pArray
|
|
23
|
+
)
|
|
24
|
+
|
|
19
25
|
# Import original e2D modules
|
|
20
26
|
from .text_renderer import DEFAULT_TEXT_STYLE, Pivots, TextRenderer, TextLabel, TextStyle
|
|
21
27
|
from .shapes import ShapeRenderer, ShapeLabel, InstancedShapeBatch, FillMode
|
|
@@ -24,48 +30,43 @@ from .commons import get_pattr, get_pattr_value, set_pattr_value, get_uniform
|
|
|
24
30
|
|
|
25
31
|
from typing import Optional
|
|
26
32
|
|
|
27
|
-
# Import
|
|
33
|
+
# Import color utilities
|
|
34
|
+
from .colors import Color, normalize_color, lerp_colors, gradient, batch_colors_to_array
|
|
35
|
+
from .color_defs import (
|
|
36
|
+
# Basic colors
|
|
37
|
+
TRANSPARENT, WHITE, BLACK, RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW,
|
|
38
|
+
# Extended colors (most common)
|
|
39
|
+
ORANGE, PURPLE, PINK, GRAY50,
|
|
40
|
+
# Lookup functions
|
|
41
|
+
COLOR_NAMES, get_color, has_color,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Try to import Cython-optimized color operations (optional batch utilities)
|
|
28
45
|
try:
|
|
29
|
-
from .
|
|
30
|
-
|
|
31
|
-
batch_add_inplace,
|
|
32
|
-
batch_scale_inplace,
|
|
33
|
-
batch_normalize_inplace,
|
|
34
|
-
vectors_to_array,
|
|
35
|
-
array_to_vectors,
|
|
36
|
-
)
|
|
37
|
-
_VECTOR_COMPILED = True
|
|
46
|
+
from . import ccolors # type: ignore[import-not-found]
|
|
47
|
+
_COLOR_COMPILED = True
|
|
38
48
|
except ImportError:
|
|
39
|
-
|
|
40
|
-
import warnings
|
|
41
|
-
warnings.warn(
|
|
42
|
-
"Vector2D compiled extension not available. "
|
|
43
|
-
"Install Cython and rebuild for optimal performance.",
|
|
44
|
-
RuntimeWarning
|
|
45
|
-
)
|
|
46
|
-
from .vectors import (
|
|
47
|
-
Vector2D,
|
|
48
|
-
batch_add_inplace,
|
|
49
|
-
batch_scale_inplace,
|
|
50
|
-
batch_normalize_inplace,
|
|
51
|
-
vectors_to_array,
|
|
52
|
-
array_to_vectors,
|
|
53
|
-
)
|
|
54
|
-
_VECTOR_COMPILED = False
|
|
49
|
+
_COLOR_COMPILED = False
|
|
55
50
|
|
|
56
|
-
# Import
|
|
51
|
+
# Import Vector2D - vectors.py handles Cython/Python fallback internally
|
|
57
52
|
from .vectors import (
|
|
53
|
+
Vector2D,
|
|
58
54
|
V2,
|
|
59
|
-
Vec2,
|
|
60
55
|
CommonVectors,
|
|
56
|
+
batch_add_inplace,
|
|
57
|
+
batch_scale_inplace,
|
|
58
|
+
batch_normalize_inplace,
|
|
59
|
+
vectors_to_array,
|
|
60
|
+
array_to_vectors,
|
|
61
61
|
lerp,
|
|
62
62
|
create_grid,
|
|
63
63
|
create_circle,
|
|
64
|
+
_COMPILED as _VECTOR_COMPILED,
|
|
64
65
|
)
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
class DefEnv:
|
|
68
|
-
ctx:
|
|
69
|
+
ctx: ContextType
|
|
69
70
|
def __init__(self) -> None: ...
|
|
70
71
|
|
|
71
72
|
def draw(self) -> None: ...
|
|
@@ -75,13 +76,29 @@ class DefEnv:
|
|
|
75
76
|
def on_resize(self, width: int, height: int) -> None: ...
|
|
76
77
|
|
|
77
78
|
class RootEnv:
|
|
79
|
+
window_size: VectorType
|
|
80
|
+
target_fps: int
|
|
81
|
+
window: WindowType
|
|
82
|
+
ctx: ContextType
|
|
83
|
+
programs: dict[str, ProgramType]
|
|
84
|
+
compute_shaders: dict[str, ComputeShaderType]
|
|
85
|
+
buffers: dict[str, BufferType]
|
|
86
|
+
keyboard: Keyboard
|
|
87
|
+
mouse: Mouse
|
|
88
|
+
text_renderer: TextRenderer
|
|
89
|
+
shape_renderer: ShapeRenderer
|
|
90
|
+
delta: float
|
|
91
|
+
last_frame_time: float
|
|
92
|
+
start_time: float
|
|
93
|
+
env: DefEnv
|
|
94
|
+
|
|
78
95
|
def __init__(
|
|
79
96
|
self,
|
|
80
|
-
window_size:tuple[int, int]=(1920, 1080),
|
|
81
|
-
target_fps:int=60,
|
|
82
|
-
vsync:bool=True,
|
|
83
|
-
version:tuple[int, int]=(4,3),
|
|
84
|
-
monitor:Optional[int]=None
|
|
97
|
+
window_size: tuple[int, int] = (1920, 1080),
|
|
98
|
+
target_fps: int = 60,
|
|
99
|
+
vsync: bool = True,
|
|
100
|
+
version: tuple[int, int] = (4, 3),
|
|
101
|
+
monitor: Optional[int] = None
|
|
85
102
|
) -> None:
|
|
86
103
|
|
|
87
104
|
if not glfw.init():
|
|
@@ -96,7 +113,7 @@ class RootEnv:
|
|
|
96
113
|
self.window_size = window_size
|
|
97
114
|
self.target_fps = target_fps
|
|
98
115
|
|
|
99
|
-
self.window
|
|
116
|
+
self.window = glfw.create_window(window_size[0], window_size[1], "e2D", monitor, None)
|
|
100
117
|
if not self.window:
|
|
101
118
|
glfw.terminate()
|
|
102
119
|
raise RuntimeError("Failed to create GLFW window")
|
|
@@ -127,9 +144,9 @@ class RootEnv:
|
|
|
127
144
|
|
|
128
145
|
glfw.set_window_size_callback(self.window, self._on_resize)
|
|
129
146
|
|
|
130
|
-
self.programs :dict[str,
|
|
131
|
-
self.compute_shaders
|
|
132
|
-
self.buffers :dict[str,
|
|
147
|
+
self.programs :dict[str, ProgramType]= {}
|
|
148
|
+
self.compute_shaders = {}
|
|
149
|
+
self.buffers :dict[str, BufferType]= {}
|
|
133
150
|
|
|
134
151
|
self.keyboard = Keyboard()
|
|
135
152
|
self.mouse = Mouse()
|
|
@@ -138,25 +155,53 @@ class RootEnv:
|
|
|
138
155
|
|
|
139
156
|
# Delta time tracking
|
|
140
157
|
self.delta = 0.0
|
|
141
|
-
self.last_frame_time = time.
|
|
158
|
+
self.last_frame_time = time.perf_counter()
|
|
159
|
+
|
|
160
|
+
# Runtime tracking (elapsed time from initialization)
|
|
161
|
+
self.start_time = time.perf_counter()
|
|
142
162
|
|
|
143
163
|
@property
|
|
144
164
|
def window_size_f(self) -> tuple[float, float]:
|
|
145
165
|
"""Get window size as floats for shader uniforms."""
|
|
146
166
|
return (float(self.window_size[0]), float(self.window_size[1]))
|
|
147
167
|
|
|
148
|
-
|
|
168
|
+
@property
|
|
169
|
+
def runtime(self) -> float:
|
|
170
|
+
"""Get total elapsed time since program initialization in seconds."""
|
|
171
|
+
return time.perf_counter() - self.start_time
|
|
172
|
+
|
|
173
|
+
def _on_resize(self, window: WindowType, width: int, height: int) -> None:
|
|
149
174
|
self.window_size = (width, height)
|
|
150
175
|
fb_size = glfw.get_framebuffer_size(window)
|
|
151
176
|
self.ctx.viewport = (0, 0, fb_size[0], fb_size[1])
|
|
152
177
|
if hasattr(self, 'env') and hasattr(self.env, 'on_resize'):
|
|
153
178
|
self.env.on_resize(fb_size[0], fb_size[1])
|
|
154
179
|
|
|
155
|
-
def init(self, env:DefEnv) -> "RootEnv":
|
|
180
|
+
def init(self, env: DefEnv) -> "RootEnv":
|
|
156
181
|
self.env = env
|
|
157
182
|
return self
|
|
158
183
|
|
|
159
|
-
def
|
|
184
|
+
def init_rec(self, fps: int = 30, draw_on_screen: bool = True, path: str = 'output.mp4') -> 'RootEnv':
|
|
185
|
+
"""Initialize screen recording.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
fps: Recording framerate (independent of application FPS)
|
|
189
|
+
draw_on_screen: Show recording stats overlay
|
|
190
|
+
path: Output video file path
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
Self for method chaining
|
|
194
|
+
|
|
195
|
+
Controls:
|
|
196
|
+
F9: Pause/Resume recording
|
|
197
|
+
F10: Restart recording (clear buffer)
|
|
198
|
+
F12: Take screenshot
|
|
199
|
+
"""
|
|
200
|
+
from .winrec import WinRec
|
|
201
|
+
self.__winrecorder__ = WinRec(self, fps=fps, draw_on_screen=draw_on_screen, path=path)
|
|
202
|
+
return self
|
|
203
|
+
|
|
204
|
+
def load_shader_file(self, path: str) -> str:
|
|
160
205
|
"""Load shader source code from a file.
|
|
161
206
|
|
|
162
207
|
Args:
|
|
@@ -171,7 +216,7 @@ class RootEnv:
|
|
|
171
216
|
with open(path, 'r', encoding='utf-8') as f:
|
|
172
217
|
return f.read()
|
|
173
218
|
|
|
174
|
-
def create_program(self, vertex_shader:str, fragment_shader:str, id:str) ->
|
|
219
|
+
def create_program(self, vertex_shader: str, fragment_shader: str, id: str) -> ProgramType:
|
|
175
220
|
new_program = self.ctx.program(
|
|
176
221
|
vertex_shader=vertex_shader,
|
|
177
222
|
fragment_shader=fragment_shader
|
|
@@ -181,7 +226,7 @@ class RootEnv:
|
|
|
181
226
|
self.programs[id] = new_program
|
|
182
227
|
return new_program
|
|
183
228
|
|
|
184
|
-
def create_program_from_files(self, vertex_path:str, fragment_path:str, id:str) ->
|
|
229
|
+
def create_program_from_files(self, vertex_path: str, fragment_path: str, id: str) -> ProgramType:
|
|
185
230
|
"""Create a shader program from shader files.
|
|
186
231
|
|
|
187
232
|
Args:
|
|
@@ -196,14 +241,19 @@ class RootEnv:
|
|
|
196
241
|
fragment_shader = self.load_shader_file(fragment_path)
|
|
197
242
|
return self.create_program(vertex_shader, fragment_shader, id)
|
|
198
243
|
|
|
199
|
-
def get_program(self, id:str) ->
|
|
244
|
+
def get_program(self, id:str) -> ProgramType | None:
|
|
200
245
|
return self.programs.get(id, None)
|
|
201
246
|
|
|
202
247
|
def __draw__(self) -> None:
|
|
203
248
|
self.ctx.clear(0.0, 0.0, 0.0, 1.0)
|
|
204
249
|
self.env.draw()
|
|
250
|
+
|
|
251
|
+
# Screen recording: capture frame before overlay, draw stats after
|
|
252
|
+
if hasattr(self, '__winrecorder__'):
|
|
253
|
+
self.__winrecorder__.update() # Captures clean frame
|
|
254
|
+
self.__winrecorder__.draw() # Draws stats overlay (not recorded)
|
|
205
255
|
|
|
206
|
-
def create_compute_shader(self, compute_shader:str, id:str) ->
|
|
256
|
+
def create_compute_shader(self, compute_shader:str, id:str) -> ComputeShaderType:
|
|
207
257
|
"""Create and store a compute shader program."""
|
|
208
258
|
new_compute = self.ctx.compute_shader(compute_shader)
|
|
209
259
|
if id in self.compute_shaders:
|
|
@@ -211,7 +261,7 @@ class RootEnv:
|
|
|
211
261
|
self.compute_shaders[id] = new_compute
|
|
212
262
|
return new_compute
|
|
213
263
|
|
|
214
|
-
def create_compute_shader_from_file(self, compute_path:str, id:str) ->
|
|
264
|
+
def create_compute_shader_from_file(self, compute_path:str, id:str) -> ComputeShaderType:
|
|
215
265
|
"""Create a compute shader from a file.
|
|
216
266
|
|
|
217
267
|
Args:
|
|
@@ -224,11 +274,11 @@ class RootEnv:
|
|
|
224
274
|
compute_shader = self.load_shader_file(compute_path)
|
|
225
275
|
return self.create_compute_shader(compute_shader, id)
|
|
226
276
|
|
|
227
|
-
def get_compute_shader(self, id:str) ->
|
|
277
|
+
def get_compute_shader(self, id:str) -> ComputeShaderType | None:
|
|
228
278
|
"""Retrieve a compute shader by id."""
|
|
229
279
|
return self.compute_shaders.get(id, None)
|
|
230
280
|
|
|
231
|
-
def create_buffer(self, data=None, reserve:int=0, id:Optional[str]=None, dynamic:bool=True) ->
|
|
281
|
+
def create_buffer(self, data=None, reserve:int=0, id:Optional[str]=None, dynamic:bool=True) -> BufferType:
|
|
232
282
|
"""Create and optionally store a buffer.
|
|
233
283
|
|
|
234
284
|
Args:
|
|
@@ -252,11 +302,11 @@ class RootEnv:
|
|
|
252
302
|
|
|
253
303
|
return buffer
|
|
254
304
|
|
|
255
|
-
def get_buffer(self, id:str) ->
|
|
305
|
+
def get_buffer(self, id:str) -> BufferType | None:
|
|
256
306
|
"""Retrieve a buffer by id."""
|
|
257
307
|
return self.buffers.get(id, None)
|
|
258
308
|
|
|
259
|
-
def bind_buffer_to_storage(self, buffer:
|
|
309
|
+
def bind_buffer_to_storage(self, buffer:BufferType|str, binding:int) -> None:
|
|
260
310
|
"""Bind a buffer to a shader storage binding point.
|
|
261
311
|
|
|
262
312
|
Args:
|
|
@@ -272,9 +322,9 @@ class RootEnv:
|
|
|
272
322
|
buffer.bind_to_storage_buffer(binding)
|
|
273
323
|
|
|
274
324
|
def dispatch_compute(self,
|
|
275
|
-
compute_id:str|
|
|
325
|
+
compute_id:str|ComputeShaderType,
|
|
276
326
|
groups_x:int=1, groups_y:int=1, groups_z:int=1,
|
|
277
|
-
buffers:Optional[dict[int,
|
|
327
|
+
buffers:Optional[dict[int, BufferType|str]]=None,
|
|
278
328
|
wait:bool=True
|
|
279
329
|
) -> None:
|
|
280
330
|
"""Dispatch a compute shader with automatic buffer binding.
|
|
@@ -304,7 +354,7 @@ class RootEnv:
|
|
|
304
354
|
if wait:
|
|
305
355
|
self.ctx.memory_barrier()
|
|
306
356
|
|
|
307
|
-
def read_buffer(self, buffer:
|
|
357
|
+
def read_buffer(self, buffer:BufferType|str, dtype='f4') -> np.ndarray:
|
|
308
358
|
"""Read data from a buffer into a numpy array.
|
|
309
359
|
|
|
310
360
|
Args:
|
|
@@ -320,7 +370,7 @@ class RootEnv:
|
|
|
320
370
|
data = np.frombuffer(buffer.read(), dtype=dtype)
|
|
321
371
|
return data
|
|
322
372
|
|
|
323
|
-
def write_buffer(self, buffer:
|
|
373
|
+
def write_buffer(self, buffer:BufferType|str, data, offset:int=0) -> None:
|
|
324
374
|
"""Write data to a buffer.
|
|
325
375
|
|
|
326
376
|
Args:
|
|
@@ -342,16 +392,16 @@ class RootEnv:
|
|
|
342
392
|
def __update__(self) -> None:
|
|
343
393
|
self.env.update()
|
|
344
394
|
|
|
345
|
-
def get_pattr(self, prog_id:str|
|
|
395
|
+
def get_pattr(self, prog_id:str|ProgramType, name:str) -> ProgramAttrType:
|
|
346
396
|
return get_pattr(prog_id, name, programs=self.programs)
|
|
347
397
|
|
|
348
|
-
def get_uniform(self, prog_id:str|
|
|
398
|
+
def get_uniform(self, prog_id:str|ProgramType|ComputeShaderType, name:str) -> UniformType:
|
|
349
399
|
return get_uniform(prog_id, name, compute_shaders=self.compute_shaders, programs=self.programs)
|
|
350
400
|
|
|
351
|
-
def get_pattr_value(self, prog_id:str|
|
|
401
|
+
def get_pattr_value(self, prog_id:str|ProgramType, name:str) -> Number|pArray:
|
|
352
402
|
return get_pattr_value(prog_id, name, programs=self.programs)
|
|
353
403
|
|
|
354
|
-
def set_pattr_value(self, prog_id:str|
|
|
404
|
+
def set_pattr_value(self, prog_id:str|ProgramType, name: str, value, *, force_write: bool= False) -> None:
|
|
355
405
|
return set_pattr_value(prog_id, name, value, force_write=force_write, programs=self.programs)
|
|
356
406
|
|
|
357
407
|
def loop(self) -> None:
|
|
@@ -364,7 +414,7 @@ class RootEnv:
|
|
|
364
414
|
target_frame_time = 1.0 / self.target_fps if (self.target_fps and self.target_fps > 0) else 0.0
|
|
365
415
|
|
|
366
416
|
while not glfw.window_should_close(self.window):
|
|
367
|
-
start_time = time.
|
|
417
|
+
start_time = time.perf_counter()
|
|
368
418
|
|
|
369
419
|
# Calculate delta time
|
|
370
420
|
self.delta = start_time - self.last_frame_time
|
|
@@ -389,20 +439,24 @@ class RootEnv:
|
|
|
389
439
|
|
|
390
440
|
# FPS Limiting
|
|
391
441
|
if target_frame_time > 0:
|
|
392
|
-
elapsed = time.
|
|
442
|
+
elapsed = time.perf_counter() - start_time
|
|
393
443
|
wait = target_frame_time - elapsed
|
|
394
444
|
if wait > 0:
|
|
395
445
|
time.sleep(wait)
|
|
396
446
|
|
|
447
|
+
# Cleanup recording before terminating
|
|
448
|
+
if hasattr(self, '__winrecorder__'):
|
|
449
|
+
self.__winrecorder__.quit()
|
|
450
|
+
|
|
397
451
|
glfw.terminate()
|
|
398
452
|
|
|
399
453
|
def print(
|
|
400
454
|
self,
|
|
401
455
|
text_or_label: str|TextLabel,
|
|
402
|
-
position:
|
|
456
|
+
position: VectorType,
|
|
403
457
|
scale: float = 1.0,
|
|
404
458
|
style: TextStyle = DEFAULT_TEXT_STYLE,
|
|
405
|
-
pivot: Pivots = Pivots.TOP_LEFT,
|
|
459
|
+
pivot: Pivots|int = Pivots.TOP_LEFT,
|
|
406
460
|
save_cache: bool = False
|
|
407
461
|
) -> Optional[TextLabel]:
|
|
408
462
|
|
|
@@ -416,15 +470,15 @@ class RootEnv:
|
|
|
416
470
|
|
|
417
471
|
# ========== Shape Drawing Methods ==========
|
|
418
472
|
|
|
419
|
-
def draw_circle(self, center:
|
|
473
|
+
def draw_circle(self, center: VectorType, radius: float, **kwargs) -> None:
|
|
420
474
|
"""Draw a circle. See ShapeRenderer.draw_circle for parameters."""
|
|
421
475
|
self.shape_renderer.draw_circle(center, radius, **kwargs)
|
|
422
476
|
|
|
423
|
-
def draw_rect(self, position:
|
|
477
|
+
def draw_rect(self, position: VectorType, size: VectorType, **kwargs) -> None:
|
|
424
478
|
"""Draw a rectangle. See ShapeRenderer.draw_rect for parameters."""
|
|
425
479
|
self.shape_renderer.draw_rect(position, size, **kwargs)
|
|
426
480
|
|
|
427
|
-
def draw_line(self, start:
|
|
481
|
+
def draw_line(self, start: VectorType, end: VectorType, **kwargs) -> None:
|
|
428
482
|
"""Draw a line. See ShapeRenderer.draw_line for parameters."""
|
|
429
483
|
self.shape_renderer.draw_line(start, end, **kwargs)
|
|
430
484
|
|
|
@@ -432,15 +486,15 @@ class RootEnv:
|
|
|
432
486
|
"""Draw a polyline. See ShapeRenderer.draw_lines for parameters."""
|
|
433
487
|
self.shape_renderer.draw_lines(points, **kwargs)
|
|
434
488
|
|
|
435
|
-
def create_circle(self, center:
|
|
489
|
+
def create_circle(self, center: VectorType, radius: float, **kwargs) -> ShapeLabel:
|
|
436
490
|
"""Create a cached circle. See ShapeRenderer.create_circle for parameters."""
|
|
437
491
|
return self.shape_renderer.create_circle(center, radius, **kwargs)
|
|
438
492
|
|
|
439
|
-
def create_rect(self, position:
|
|
493
|
+
def create_rect(self, position: VectorType, size: VectorType, **kwargs) -> ShapeLabel:
|
|
440
494
|
"""Create a cached rectangle. See ShapeRenderer.create_rect for parameters."""
|
|
441
495
|
return self.shape_renderer.create_rect(position, size, **kwargs)
|
|
442
496
|
|
|
443
|
-
def create_line(self, start:
|
|
497
|
+
def create_line(self, start: VectorType, end: VectorType, **kwargs) -> ShapeLabel:
|
|
444
498
|
"""Create a cached line. See ShapeRenderer.create_line for parameters."""
|
|
445
499
|
return self.shape_renderer.create_line(start, end, **kwargs)
|
|
446
500
|
|
|
@@ -458,4 +512,77 @@ class RootEnv:
|
|
|
458
512
|
|
|
459
513
|
def create_line_batch(self, max_shapes: int = 10000) -> InstancedShapeBatch:
|
|
460
514
|
"""Create a batch for drawing multiple lines using GPU instancing."""
|
|
461
|
-
return self.shape_renderer.create_line_batch(max_shapes)
|
|
515
|
+
return self.shape_renderer.create_line_batch(max_shapes)
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
# Export all public symbols for easy access
|
|
519
|
+
__all__ = [
|
|
520
|
+
# Version info
|
|
521
|
+
'__version__',
|
|
522
|
+
'__author__',
|
|
523
|
+
'__email__',
|
|
524
|
+
# Core classes
|
|
525
|
+
'RootEnv',
|
|
526
|
+
'DefEnv',
|
|
527
|
+
# Vector classes and utilities
|
|
528
|
+
'Vector2D',
|
|
529
|
+
'V2',
|
|
530
|
+
'CommonVectors',
|
|
531
|
+
'batch_add_inplace',
|
|
532
|
+
'batch_scale_inplace',
|
|
533
|
+
'batch_normalize_inplace',
|
|
534
|
+
'vectors_to_array',
|
|
535
|
+
'array_to_vectors',
|
|
536
|
+
'lerp',
|
|
537
|
+
'create_grid',
|
|
538
|
+
'create_circle',
|
|
539
|
+
# Type aliases
|
|
540
|
+
'VectorType',
|
|
541
|
+
'ColorType',
|
|
542
|
+
# Color utilities
|
|
543
|
+
'Color',
|
|
544
|
+
'normalize_color',
|
|
545
|
+
'lerp_colors',
|
|
546
|
+
'gradient',
|
|
547
|
+
'batch_colors_to_array',
|
|
548
|
+
# Pre-defined colors
|
|
549
|
+
'TRANSPARENT',
|
|
550
|
+
'WHITE',
|
|
551
|
+
'BLACK',
|
|
552
|
+
'RED',
|
|
553
|
+
'GREEN',
|
|
554
|
+
'BLUE',
|
|
555
|
+
'CYAN',
|
|
556
|
+
'MAGENTA',
|
|
557
|
+
'YELLOW',
|
|
558
|
+
'ORANGE',
|
|
559
|
+
'PURPLE',
|
|
560
|
+
'PINK',
|
|
561
|
+
'GRAY50',
|
|
562
|
+
'COLOR_NAMES',
|
|
563
|
+
'get_color',
|
|
564
|
+
'has_color',
|
|
565
|
+
# Text rendering
|
|
566
|
+
'TextRenderer',
|
|
567
|
+
'TextLabel',
|
|
568
|
+
'TextStyle',
|
|
569
|
+
'Pivots',
|
|
570
|
+
'DEFAULT_TEXT_STYLE',
|
|
571
|
+
# Shape rendering
|
|
572
|
+
'ShapeRenderer',
|
|
573
|
+
'ShapeLabel',
|
|
574
|
+
'InstancedShapeBatch',
|
|
575
|
+
'FillMode',
|
|
576
|
+
# Input devices
|
|
577
|
+
'Keyboard',
|
|
578
|
+
'Mouse',
|
|
579
|
+
'KeyState',
|
|
580
|
+
# ModernGL utilities
|
|
581
|
+
'get_pattr',
|
|
582
|
+
'get_pattr_value',
|
|
583
|
+
'set_pattr_value',
|
|
584
|
+
'get_uniform',
|
|
585
|
+
# Compilation flags
|
|
586
|
+
'_VECTOR_COMPILED',
|
|
587
|
+
'_COLOR_COMPILED',
|
|
588
|
+
]
|
e2D/__init__.pyi
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Type stubs for e2D package
|
|
3
|
+
High-Performance 2D Graphics and Math Library
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import Optional, Any
|
|
8
|
+
from .types import BufferType, ComputeShaderType, ContextType, Number, ProgramAttrType, ProgramType, ProgramType, UniformType, VectorType, pArray
|
|
9
|
+
from .text_renderer import DEFAULT_TEXT_STYLE, Pivots, TextRenderer, TextLabel, TextStyle
|
|
10
|
+
from .shapes import ShapeRenderer, ShapeLabel, InstancedShapeBatch
|
|
11
|
+
from .devices import Keyboard, Mouse
|
|
12
|
+
|
|
13
|
+
__version__: str
|
|
14
|
+
__author__: str
|
|
15
|
+
__email__: str
|
|
16
|
+
|
|
17
|
+
_VECTOR_COMPILED: bool
|
|
18
|
+
|
|
19
|
+
class DefEnv:
|
|
20
|
+
"""Base environment class for user environments"""
|
|
21
|
+
ctx: ContextType
|
|
22
|
+
|
|
23
|
+
def __init__(self) -> None: ...
|
|
24
|
+
def draw(self) -> None: ...
|
|
25
|
+
def update(self) -> None: ...
|
|
26
|
+
def on_resize(self, width: int, height: int) -> None: ...
|
|
27
|
+
|
|
28
|
+
class RootEnv:
|
|
29
|
+
"""Root environment managing the window, context, and main loop"""
|
|
30
|
+
window: Any # glfw._GLFWwindow
|
|
31
|
+
window_size: tuple[int, int]
|
|
32
|
+
target_fps: int
|
|
33
|
+
ctx: ContextType
|
|
34
|
+
programs: dict[str, ProgramType]
|
|
35
|
+
compute_shaders: dict[str, ComputeShaderType]
|
|
36
|
+
buffers: dict[str, BufferType]
|
|
37
|
+
keyboard: Keyboard
|
|
38
|
+
mouse: Mouse
|
|
39
|
+
text_renderer: TextRenderer
|
|
40
|
+
shape_renderer: ShapeRenderer
|
|
41
|
+
delta: float
|
|
42
|
+
last_frame_time: float
|
|
43
|
+
start_time: float
|
|
44
|
+
env: DefEnv
|
|
45
|
+
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
window_size: tuple[int, int] = (1920, 1080),
|
|
49
|
+
target_fps: int = 60,
|
|
50
|
+
vsync: bool = True,
|
|
51
|
+
version: tuple[int, int] = (4, 3),
|
|
52
|
+
monitor: Optional[int] = None
|
|
53
|
+
) -> None: ...
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def window_size_f(self) -> tuple[float, float]:
|
|
57
|
+
"""Get window size as floats for shader uniforms."""
|
|
58
|
+
...
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def runtime(self) -> float:
|
|
62
|
+
"""Get total elapsed time since program initialization in seconds."""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
def init(self, env: DefEnv) -> "RootEnv": ...
|
|
66
|
+
|
|
67
|
+
def load_shader_file(self, path: str) -> str:
|
|
68
|
+
"""Load shader source code from a file."""
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
def create_program(self, vertex_shader: str, fragment_shader: str, id: str) -> ProgramType: ...
|
|
72
|
+
def create_program_from_files(self, vertex_path: str, fragment_path: str, id: str) -> ProgramType: ...
|
|
73
|
+
def get_program(self, id: str) -> Optional[ProgramType]: ...
|
|
74
|
+
|
|
75
|
+
def create_compute_shader(self, compute_shader: str, id: str) -> ComputeShaderType: ...
|
|
76
|
+
def create_compute_shader_from_file(self, compute_path: str, id: str) -> ComputeShaderType: ...
|
|
77
|
+
def get_compute_shader(self, id: str) -> Optional[ComputeShaderType]: ...
|
|
78
|
+
|
|
79
|
+
def create_buffer(
|
|
80
|
+
self,
|
|
81
|
+
data: Any = None,
|
|
82
|
+
reserve: int = 0,
|
|
83
|
+
id: Optional[str] = None,
|
|
84
|
+
dynamic: bool = True
|
|
85
|
+
) -> BufferType: ...
|
|
86
|
+
|
|
87
|
+
def get_buffer(self, id: str) -> Optional[BufferType]: ...
|
|
88
|
+
def bind_buffer_to_storage(self, buffer: BufferType | str, binding: int) -> None: ...
|
|
89
|
+
|
|
90
|
+
def dispatch_compute(
|
|
91
|
+
self,
|
|
92
|
+
compute_id: str | ComputeShaderType,
|
|
93
|
+
groups_x: int = 1,
|
|
94
|
+
groups_y: int = 1,
|
|
95
|
+
groups_z: int = 1,
|
|
96
|
+
buffers: Optional[dict[int, BufferType | str]] = None,
|
|
97
|
+
wait: bool = True
|
|
98
|
+
) -> None: ...
|
|
99
|
+
|
|
100
|
+
def read_buffer(self, buffer: BufferType | str, dtype: str = 'f4') -> np.ndarray: ...
|
|
101
|
+
def write_buffer(self, buffer: BufferType | str, data: Any, offset: int = 0) -> None: ...
|
|
102
|
+
|
|
103
|
+
def get_pattr(
|
|
104
|
+
self,
|
|
105
|
+
prog_id: str | ProgramType,
|
|
106
|
+
name: str
|
|
107
|
+
) -> ProgramAttrType: ...
|
|
108
|
+
|
|
109
|
+
def get_uniform(
|
|
110
|
+
self,
|
|
111
|
+
prog_id: str | ProgramType | ComputeShaderType,
|
|
112
|
+
name: str
|
|
113
|
+
) -> UniformType: ...
|
|
114
|
+
|
|
115
|
+
def get_pattr_value(self, prog_id: str | ProgramType, name: str) -> Number | pArray: ...
|
|
116
|
+
def set_pattr_value(self, prog_id: str | ProgramType, name: str, value: Any, *, force_write: bool = False) -> None: ...
|
|
117
|
+
|
|
118
|
+
def loop(self) -> None:
|
|
119
|
+
"""Main rendering loop"""
|
|
120
|
+
...
|
|
121
|
+
|
|
122
|
+
def print(
|
|
123
|
+
self,
|
|
124
|
+
text_or_label: str | TextLabel,
|
|
125
|
+
position: VectorType,
|
|
126
|
+
scale: float = 1.0,
|
|
127
|
+
style: TextStyle = DEFAULT_TEXT_STYLE,
|
|
128
|
+
pivot: Pivots|int = Pivots.TOP_LEFT,
|
|
129
|
+
save_cache: bool = False
|
|
130
|
+
) -> Optional[TextLabel]: ...
|
|
131
|
+
|
|
132
|
+
# Shape drawing methods
|
|
133
|
+
def draw_circle(self, center: VectorType, radius: float, **kwargs: Any) -> None: ...
|
|
134
|
+
def draw_rect(self, position: VectorType, size: VectorType, **kwargs: Any) -> None: ...
|
|
135
|
+
def draw_line(self, start: VectorType, end: VectorType, **kwargs: Any) -> None: ...
|
|
136
|
+
def draw_lines(self, points: Any, **kwargs: Any) -> None: ...
|
|
137
|
+
|
|
138
|
+
def create_circle(self, center: VectorType, radius: float, **kwargs: Any) -> ShapeLabel: ...
|
|
139
|
+
def create_rect(self, position: VectorType, size: VectorType, **kwargs: Any) -> ShapeLabel: ...
|
|
140
|
+
def create_line(self, start: VectorType, end: VectorType, **kwargs: Any) -> ShapeLabel: ...
|
|
141
|
+
def create_lines(self, points: Any, **kwargs: Any) -> ShapeLabel: ...
|
|
142
|
+
|
|
143
|
+
def create_circle_batch(self, max_shapes: int = 10000) -> InstancedShapeBatch: ...
|
|
144
|
+
def create_rect_batch(self, max_shapes: int = 10000) -> InstancedShapeBatch: ...
|
|
145
|
+
def create_line_batch(self, max_shapes: int = 10000) -> InstancedShapeBatch: ...
|