10
10
11
11
import array
12
12
import math
13
- from typing import Optional , Tuple
13
+ from typing import Optional , Tuple , List
14
14
15
15
import PIL .Image
16
16
import PIL .ImageOps
17
17
import PIL .ImageDraw
18
18
19
19
import pyglet .gl as gl
20
20
21
- from arcade .types import Color , RGBA255 , PointList
21
+ from arcade .types import Color , RGBA255 , PointList , Point
22
22
from arcade .earclip import earclip
23
23
from .math import rotate_point
24
24
from arcade import (
@@ -293,20 +293,17 @@ def draw_ellipse_filled(center_x: float, center_y: float,
293
293
The default value of -1 means arcade will try to calculate a reasonable
294
294
amount of segments based on the size of the circle.
295
295
"""
296
+ # Fail immediately if we have no window or context
296
297
window = get_window ()
297
298
ctx = window .ctx
298
-
299
299
program = ctx .shape_ellipse_filled_unbuffered_program
300
300
geometry = ctx .shape_ellipse_unbuffered_geometry
301
301
buffer = ctx .shape_ellipse_unbuffered_buffer
302
- # We need to normalize the color because we are setting it as a float uniform
303
- if len (color ) == 3 :
304
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , 1.0
305
- elif len (color ) == 4 :
306
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , color [3 ] / 255 # type: ignore
307
- else :
308
- raise ValueError ("Invalid color format. Use a 3 or 4 component tuple" )
309
302
303
+ # Normalize the color because this shader takes a float uniform
304
+ color_normalized = Color .from_iterable (color ).normalized
305
+
306
+ # Pass data to the shader
310
307
program ['color' ] = color_normalized
311
308
program ['shape' ] = width / 2 , height / 2 , tilt_angle
312
309
program ['segments' ] = num_segments
@@ -339,20 +336,17 @@ def draw_ellipse_outline(center_x: float, center_y: float,
339
336
The default value of -1 means arcade will try to calculate a reasonable
340
337
amount of segments based on the size of the circle.
341
338
"""
339
+ # Fail immediately if we have no window or context
342
340
window = get_window ()
343
341
ctx = window .ctx
344
-
345
342
program = ctx .shape_ellipse_outline_unbuffered_program
346
343
geometry = ctx .shape_ellipse_outline_unbuffered_geometry
347
344
buffer = ctx .shape_ellipse_outline_unbuffered_buffer
348
- # We need to normalize the color because we are setting it as a float uniform
349
- if len (color ) == 3 :
350
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , 1.0
351
- elif len (color ) == 4 :
352
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , color [3 ] / 255 # type: ignore
353
- else :
354
- raise ValueError ("Invalid color format. Use a 3 or 4 component tuple" )
355
345
346
+ # Normalize the color because this shader takes a float uniform
347
+ color_normalized = Color .from_iterable (color ).normalized
348
+
349
+ # Pass data to shader
356
350
program ['color' ] = color_normalized
357
351
program ['shape' ] = width / 2 , height / 2 , tilt_angle , border_width
358
352
program ['segments' ] = num_segments
@@ -380,29 +374,36 @@ def _generic_draw_line_strip(point_list: PointList,
380
374
:param color: A color, specified as an RGBA tuple or a
381
375
:py:class:`~arcade.types.Color` instance.
382
376
"""
377
+ # Fail if we don't have a window, context, or right GL abstractions
383
378
window = get_window ()
384
379
ctx = window .ctx
385
-
386
- c4 = Color .from_iterable (color )
387
- c4e = c4 * len (point_list )
388
- a = array .array ('B' , c4e )
389
- vertices = array .array ('f' , tuple (item for sublist in point_list for item in sublist ))
390
-
391
380
geometry = ctx .generic_draw_line_strip_geometry
381
+ vertex_buffer = ctx .generic_draw_line_strip_vbo
382
+ color_buffer = ctx .generic_draw_line_strip_color
392
383
program = ctx .line_vertex_shader
393
- geometry .num_vertices = len (point_list )
394
384
395
- # Double buffer sizes if out of space
396
- while len (vertices ) * 4 > ctx .generic_draw_line_strip_vbo .size :
397
- ctx .generic_draw_line_strip_vbo .orphan (ctx .generic_draw_line_strip_vbo .size * 2 )
398
- ctx .generic_draw_line_strip_color .orphan (ctx .generic_draw_line_strip_color .size * 2 )
385
+ # Validate and alpha-pad color, then expand to multi-vertex form since
386
+ # this shader normalizes internally as if made to draw multicolor lines.
387
+ rgba = Color .from_iterable (color )
388
+ num_vertices = len (point_list ) # Fail if it isn't a sized / sequence object
389
+
390
+ # Translate Python objects into types arcade's Buffer objects accept
391
+ color_array = array .array ('B' , rgba * num_vertices )
392
+ vertex_array = array .array ('f' , tuple (item for sublist in point_list for item in sublist ))
393
+ geometry .num_vertices = num_vertices
394
+
395
+ # Double buffer sizes until they can hold all our data
396
+ goal_vertex_buffer_size = len (vertex_array ) * 4
397
+ while goal_vertex_buffer_size > vertex_buffer .size :
398
+ vertex_buffer .orphan (color_buffer .size * 2 )
399
+ color_buffer .orphan (color_buffer .size * 2 )
399
400
else :
400
- ctx .generic_draw_line_strip_vbo .orphan ()
401
- ctx .generic_draw_line_strip_color .orphan ()
402
-
403
- ctx .generic_draw_line_strip_vbo .write (vertices )
404
- ctx .generic_draw_line_strip_color .write (a )
401
+ vertex_buffer .orphan ()
402
+ color_buffer .orphan ()
405
403
404
+ # Write data & render
405
+ vertex_buffer .write (vertex_array )
406
+ color_buffer .write (color_array )
406
407
geometry .render (program , mode = mode )
407
408
408
409
@@ -419,7 +420,7 @@ def draw_line_strip(point_list: PointList,
419
420
if line_width == 1 :
420
421
_generic_draw_line_strip (point_list , color , gl .GL_LINE_STRIP )
421
422
else :
422
- triangle_point_list : PointList = []
423
+ triangle_point_list : List [ Point ] = []
423
424
# This needs a lot of improvement
424
425
last_point = None
425
426
for point in point_list :
@@ -444,24 +445,23 @@ def draw_line(start_x: float, start_y: float, end_x: float, end_y: float,
444
445
:py:class:`~arcade.types.Color` instance.
445
446
:param line_width: Width of the line in pixels.
446
447
"""
448
+ # Fail if we don't have a window, context, or right GL abstractions
447
449
window = get_window ()
448
450
ctx = window .ctx
449
-
450
451
program = ctx .shape_line_program
451
452
geometry = ctx .shape_line_geometry
452
- # We need to normalize the color because we are setting it as a float uniform
453
- if len (color ) == 3 :
454
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , 1.0
455
- elif len (color ) == 4 :
456
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , color [3 ] / 255 # type: ignore
457
- else :
458
- raise ValueError ("Invalid color format. Use a 3 or 4 component tuple" )
453
+ line_pos_buffer = ctx .shape_line_buffer_pos
459
454
460
- program ['line_width' ] = line_width
455
+ # Validate & normalize to a pass the shader an RGBA float uniform
456
+ color_normalized = Color .from_iterable (color ).normalized
457
+
458
+ # Pass data to the shader
461
459
program ['color' ] = color_normalized
462
- ctx .shape_line_buffer_pos .orphan () # Allocate new buffer internally
463
- ctx .shape_line_buffer_pos .write (
460
+ program ['line_width' ] = line_width
461
+ line_pos_buffer .orphan () # Allocate new buffer internally
462
+ line_pos_buffer .write (
464
463
data = array .array ('f' , (start_x , start_y , end_x , end_y )))
464
+
465
465
geometry .render (program , mode = gl .GL_LINES , vertices = 2 )
466
466
467
467
@@ -479,29 +479,32 @@ def draw_lines(point_list: PointList,
479
479
:py:class:`~arcade.types.Color` instance.
480
480
:param line_width: Width of the line in pixels.
481
481
"""
482
+ # Fail if we don't have a window, context, or right GL abstractions
482
483
window = get_window ()
483
484
ctx = window .ctx
484
-
485
485
program = ctx .shape_line_program
486
486
geometry = ctx .shape_line_geometry
487
- # We need to normalize the color because we are setting it as a float uniform
488
- if len (color ) == 3 :
489
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , 1.0
490
- elif len (color ) == 4 :
491
- color_normalized = color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , color [3 ] / 255 # type: ignore
492
- else :
493
- raise ValueError ("Invalid color format. Use a 3 or 4 component tuple" )
487
+ line_buffer_pos = ctx .shape_line_buffer_pos
488
+
489
+ # Validate & normalize to a pass the shader an RGBA float uniform
490
+ color_normalized = Color .from_iterable (color ).normalized
494
491
495
- while len (point_list ) * 3 * 4 > ctx .shape_line_buffer_pos .size :
496
- ctx .shape_line_buffer_pos .orphan (ctx .shape_line_buffer_pos .size * 2 )
492
+ line_pos_array = array .array ('f' , (v for point in point_list for v in point ))
493
+ num_points = len (point_list )
494
+
495
+ # Grow buffer until large enough to hold all our data
496
+ goal_buffer_size = num_points * 3 * 4
497
+ while goal_buffer_size > line_buffer_pos .size :
498
+ ctx .shape_line_buffer_pos .orphan (line_buffer_pos .size * 2 )
497
499
else :
498
500
ctx .shape_line_buffer_pos .orphan ()
499
501
502
+ # Pass data to shader
500
503
program ['line_width' ] = line_width
501
504
program ['color' ] = color_normalized
502
- ctx . shape_line_buffer_pos . write (
503
- data = array . array ( 'f' , tuple ( v for point in point_list for v in point )))
504
- geometry .render (program , mode = gl .GL_LINES , vertices = len ( point_list ) )
505
+ line_buffer_pos . write (data = line_pos_array )
506
+
507
+ geometry .render (program , mode = gl .GL_LINES , vertices = num_points )
505
508
506
509
507
510
# --- BEGIN POINT FUNCTIONS # # #
@@ -530,28 +533,31 @@ def draw_points(point_list: PointList, color: RGBA255, size: float = 1):
530
533
:py:class:`~arcade.types.Color` instance.
531
534
:param size: Size of the point in pixels.
532
535
"""
536
+ # Fails immediately if we don't have a window or context
533
537
window = get_window ()
534
538
ctx = window .ctx
535
-
536
539
program = ctx .shape_rectangle_filled_unbuffered_program
537
540
geometry = ctx .shape_rectangle_filled_unbuffered_geometry
538
541
buffer = ctx .shape_rectangle_filled_unbuffered_buffer
539
- # We need to normalize the color because we are setting it as a float uniform
540
- if len ( color ) == 3 :
541
- color_normalized = color [ 0 ] / 255 , color [ 1 ] / 255 , color [ 2 ] / 255 , 1.0
542
- elif len ( color ) == 4 :
543
- color_normalized = color [ 0 ] / 255 , color [ 1 ] / 255 , color [ 2 ] / 255 , color [ 3 ] / 255 # type: ignore
544
- else :
545
- raise ValueError ( "Invalid color format. Use a 3 or 4 component tuple" )
542
+
543
+ # Validate & normalize to a pass the shader an RGBA float uniform
544
+ color_normalized = Color . from_iterable ( color ). normalized
545
+
546
+ # Get # of points and translate Python tuples to a C-style array
547
+ num_points = len ( point_list )
548
+ point_array = array . array ( 'f' , ( v for point in point_list for v in point ) )
546
549
547
550
# Resize buffer
548
- data_size = len ( point_list ) * 8
551
+ data_size = num_points * 8
549
552
# if data_size > buffer.size:
550
553
buffer .orphan (size = data_size )
551
554
555
+ # Pass data to shader
552
556
program ['color' ] = color_normalized
553
557
program ['shape' ] = size , size , 0
554
- buffer .write (data = array .array ('f' , tuple (v for point in point_list for v in point )))
558
+ buffer .write (data = point_array )
559
+
560
+ # Only render the # of points we have complete data for
555
561
geometry .render (program , mode = ctx .POINTS , vertices = data_size // 8 )
556
562
557
563
@@ -585,22 +591,29 @@ def draw_polygon_outline(point_list: PointList,
585
591
:py:class:`~arcade.types.Color` instance.
586
592
:param line_width: Width of the line in pixels.
587
593
"""
594
+ # Convert to modifiable list & close the loop
588
595
new_point_list = list (point_list )
589
596
new_point_list .append (point_list [0 ])
590
597
598
+ # Create a place to store the triangles we'll use to thicken the line
591
599
triangle_point_list = []
600
+
592
601
# This needs a lot of improvement
593
602
last_point = None
594
603
for point in new_point_list :
595
604
if last_point is not None :
596
- points = get_points_for_thick_line (last_point [0 ], last_point [1 ], point [0 ], point [1 ], line_width )
605
+ # Calculate triangles, then re-order to link up the quad?
606
+ points = get_points_for_thick_line (* last_point , * point , line_width )
597
607
reordered_points = points [1 ], points [0 ], points [2 ], points [3 ]
608
+
598
609
triangle_point_list .extend (reordered_points )
599
610
last_point = point
600
611
601
- points = get_points_for_thick_line (new_point_list [0 ][0 ], new_point_list [0 ][1 ], new_point_list [1 ][0 ],
602
- new_point_list [1 ][1 ], line_width )
612
+ # Use first two points of new list to close the loop
613
+ new_start , new_next = new_point_list [:2 ]
614
+ points = get_points_for_thick_line (* new_start , * new_next , line_width )
603
615
triangle_point_list .append (points [1 ])
616
+
604
617
_generic_draw_line_strip (triangle_point_list , color , gl .GL_TRIANGLE_STRIP )
605
618
606
619
@@ -875,24 +888,22 @@ def draw_rectangle_filled(center_x: float, center_y: float, width: float,
875
888
:py:class:`tuple` or :py:class`~arcade.types.Color` instance.
876
889
:param tilt_angle: rotation of the rectangle (clockwise). Defaults to zero.
877
890
"""
891
+ # Fail if we don't have a window, context, or right GL abstractions
878
892
window = get_window ()
879
893
ctx = window .ctx
880
-
881
894
program = ctx .shape_rectangle_filled_unbuffered_program
882
895
geometry = ctx .shape_rectangle_filled_unbuffered_geometry
883
896
buffer = ctx .shape_rectangle_filled_unbuffered_buffer
884
- # We need to normalize the color because we are setting it as a float uniform
885
- if len (color ) == 3 :
886
- color_normalized = (color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , 1.0 )
887
- elif len (color ) == 4 :
888
- color_normalized = (color [0 ] / 255 , color [1 ] / 255 , color [2 ] / 255 , color [3 ] / 255 ) # type: ignore
889
- else :
890
- raise ValueError ("Invalid color format. Use a 3 or 4 component tuple" )
891
897
898
+ # Validate & normalize to a pass the shader an RGBA float uniform
899
+ color_normalized = Color .from_iterable (color ).normalized
900
+
901
+ # Pass data to the shader
892
902
program ['color' ] = color_normalized
893
903
program ['shape' ] = width , height , tilt_angle
894
904
buffer .orphan ()
895
905
buffer .write (data = array .array ('f' , (center_x , center_y )))
906
+
896
907
geometry .render (program , mode = ctx .POINTS , vertices = 1 )
897
908
898
909
0 commit comments