1
+ from array import array
1
2
from contextlib import contextmanager
2
3
from typing import Generator
3
4
4
5
from PIL import Image
6
+ from pyglet .math import Vec2 , Vec4
5
7
from typing_extensions import Self
6
8
7
9
import arcade
8
10
from arcade import Texture
9
11
from arcade .camera import CameraData , OrthographicProjectionData , OrthographicProjector
10
12
from arcade .color import TRANSPARENT_BLACK
11
- from arcade .gl import Framebuffer
13
+ from arcade .gl import BufferDescription , Framebuffer
12
14
from arcade .gui .nine_patch import NinePatchTexture
13
15
from arcade .types import LBWH , RGBA255 , Point , Rect
14
16
@@ -53,12 +55,17 @@ def __init__(
53
55
* self .ctx .BLEND_DEFAULT ,
54
56
)
55
57
56
- self ._geometry = self .ctx .geometry ()
58
+ # 5 floats per vertex (pos 3f, tex 2f) with 4 vertices
59
+ self ._buffer = self .ctx .buffer (reserve = 4 * 5 * 4 )
60
+ self ._geometry = self .ctx .geometry (
61
+ content = [BufferDescription (self ._buffer , "3f 2f" , ["in_pos" , "in_uv" ])],
62
+ mode = self .ctx .TRIANGLE_STRIP ,
63
+ )
57
64
self ._program = self .ctx .load_program (
58
65
vertex_shader = ":system:shaders/gui/surface_vs.glsl" ,
59
- geometry_shader = ":system:shaders/gui/surface_gs.glsl" ,
60
66
fragment_shader = ":system:shaders/gui/surface_fs.glsl" ,
61
67
)
68
+ self ._update_geometry ()
62
69
63
70
self ._cam = OrthographicProjector (
64
71
view = CameraData (),
@@ -228,6 +235,8 @@ def draw(
228
235
area: Limit the area in the surface we're drawing
229
236
(l, b, w, h)
230
237
"""
238
+ self ._update_geometry (area = area )
239
+
231
240
# Set blend function
232
241
blend_func = self .ctx .blend_func
233
242
self .ctx .blend_func = self .blend_func_render
@@ -239,10 +248,7 @@ def draw(
239
248
self .texture .filter = self .ctx .LINEAR , self .ctx .LINEAR
240
249
241
250
self .texture .use (0 )
242
- self ._program ["pos" ] = self ._pos
243
- self ._program ["size" ] = self ._size
244
- self ._program ["area" ] = (0 , 0 , * self ._size ) if not area else area .lbwh
245
- self ._geometry .render (self ._program , vertices = 1 )
251
+ self ._geometry .render (self ._program )
246
252
247
253
# Restore blend function
248
254
self .ctx .blend_func = blend_func
@@ -267,3 +273,47 @@ def resize(self, *, size: tuple[int, int], pixel_ratio: float) -> None:
267
273
def to_image (self ) -> Image .Image :
268
274
"""Convert the surface to an PIL image"""
269
275
return self .ctx .get_framebuffer_image (self .fbo )
276
+
277
+ def _update_geometry (self , area : Rect | None = None ) -> None :
278
+ """
279
+ Update the internal geometry of the surface mesh.
280
+
281
+ The geometry is a triangle strip with 4 verties.
282
+ """
283
+ if area is None :
284
+ area = LBWH (0 , 0 , * self .size )
285
+
286
+ # Clamp the area inside the surface
287
+ # This is the local area inside the surface
288
+ _size = Vec2 (* self .size )
289
+ _pos = Vec2 (area .left , area .bottom )
290
+ _area_size = Vec2 (area .width , area .height )
291
+
292
+ b1 = _pos .clamp (Vec2 (0.0 ), _size )
293
+ end_point = _pos + _area_size
294
+ b2 = end_point .clamp (Vec2 (0.0 ), _size )
295
+ b = b2 - b1
296
+ l_area = Vec4 (b1 .x , b1 .y , b .x , b .y )
297
+
298
+ # Create the 4 corners of the rectangle
299
+ # These are the final/global coordinates rendered
300
+ p_ll = _pos + l_area .xy # type: ignore
301
+ p_lr = _pos + l_area .xy + Vec2 (l_area .z , 0.0 ) # type: ignore
302
+ p_ul = _pos + l_area .xy + Vec2 (0.0 , l_area .w ) # type: ignore
303
+ p_ur = _pos + l_area .xy + l_area .zw # type: ignore
304
+
305
+ # Calculate the UV coordinates
306
+ bottom = l_area .y / _size .y
307
+ left = l_area .x / _size .x
308
+ top = (l_area .y + l_area .w ) / _size .y
309
+ right = (l_area .x + l_area .z ) / _size .x
310
+
311
+ # fmt: off
312
+ vertices = array ("f" , (
313
+ p_ll .x , p_ll .y , 0.0 , left , bottom ,
314
+ p_lr .x , p_lr .y , 0.0 , right , bottom ,
315
+ p_ul .x , p_ul .y , 0.0 , left , top ,
316
+ p_ur .x , p_ur .y , 0.0 , right , top ,
317
+ ))
318
+ # fmt: on
319
+ self ._buffer .write (vertices )
0 commit comments