1010
1111import array
1212import math
13- from typing import Optional , Tuple
13+ from typing import Optional , Tuple , List
1414
1515import PIL .Image
1616import PIL .ImageOps
1717import PIL .ImageDraw
1818
1919import pyglet .gl as gl
2020
21- from arcade .types import Color , RGBA255 , PointList
21+ from arcade .types import Color , RGBA255 , PointList , Point
2222from arcade .earclip import earclip
2323from .math import rotate_point
2424from arcade import (
@@ -293,20 +293,17 @@ def draw_ellipse_filled(center_x: float, center_y: float,
293293 The default value of -1 means arcade will try to calculate a reasonable
294294 amount of segments based on the size of the circle.
295295 """
296+ # Fail immediately if we have no window or context
296297 window = get_window ()
297298 ctx = window .ctx
298-
299299 program = ctx .shape_ellipse_filled_unbuffered_program
300300 geometry = ctx .shape_ellipse_unbuffered_geometry
301301 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" )
309302
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
310307 program ['color' ] = color_normalized
311308 program ['shape' ] = width / 2 , height / 2 , tilt_angle
312309 program ['segments' ] = num_segments
@@ -339,20 +336,17 @@ def draw_ellipse_outline(center_x: float, center_y: float,
339336 The default value of -1 means arcade will try to calculate a reasonable
340337 amount of segments based on the size of the circle.
341338 """
339+ # Fail immediately if we have no window or context
342340 window = get_window ()
343341 ctx = window .ctx
344-
345342 program = ctx .shape_ellipse_outline_unbuffered_program
346343 geometry = ctx .shape_ellipse_outline_unbuffered_geometry
347344 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" )
355345
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
356350 program ['color' ] = color_normalized
357351 program ['shape' ] = width / 2 , height / 2 , tilt_angle , border_width
358352 program ['segments' ] = num_segments
@@ -380,29 +374,36 @@ def _generic_draw_line_strip(point_list: PointList,
380374 :param color: A color, specified as an RGBA tuple or a
381375 :py:class:`~arcade.types.Color` instance.
382376 """
377+ # Fail if we don't have a window, context, or right GL abstractions
383378 window = get_window ()
384379 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-
391380 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
392383 program = ctx .line_vertex_shader
393- geometry .num_vertices = len (point_list )
394384
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 )
399400 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 ()
405403
404+ # Write data & render
405+ vertex_buffer .write (vertex_array )
406+ color_buffer .write (color_array )
406407 geometry .render (program , mode = mode )
407408
408409
@@ -419,7 +420,7 @@ def draw_line_strip(point_list: PointList,
419420 if line_width == 1 :
420421 _generic_draw_line_strip (point_list , color , gl .GL_LINE_STRIP )
421422 else :
422- triangle_point_list : PointList = []
423+ triangle_point_list : List [ Point ] = []
423424 # This needs a lot of improvement
424425 last_point = None
425426 for point in point_list :
@@ -444,24 +445,23 @@ def draw_line(start_x: float, start_y: float, end_x: float, end_y: float,
444445 :py:class:`~arcade.types.Color` instance.
445446 :param line_width: Width of the line in pixels.
446447 """
448+ # Fail if we don't have a window, context, or right GL abstractions
447449 window = get_window ()
448450 ctx = window .ctx
449-
450451 program = ctx .shape_line_program
451452 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
459454
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
461459 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 (
464463 data = array .array ('f' , (start_x , start_y , end_x , end_y )))
464+
465465 geometry .render (program , mode = gl .GL_LINES , vertices = 2 )
466466
467467
@@ -479,29 +479,32 @@ def draw_lines(point_list: PointList,
479479 :py:class:`~arcade.types.Color` instance.
480480 :param line_width: Width of the line in pixels.
481481 """
482+ # Fail if we don't have a window, context, or right GL abstractions
482483 window = get_window ()
483484 ctx = window .ctx
484-
485485 program = ctx .shape_line_program
486486 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
494491
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 )
497499 else :
498500 ctx .shape_line_buffer_pos .orphan ()
499501
502+ # Pass data to shader
500503 program ['line_width' ] = line_width
501504 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 )
505508
506509
507510# --- BEGIN POINT FUNCTIONS # # #
@@ -530,28 +533,31 @@ def draw_points(point_list: PointList, color: RGBA255, size: float = 1):
530533 :py:class:`~arcade.types.Color` instance.
531534 :param size: Size of the point in pixels.
532535 """
536+ # Fails immediately if we don't have a window or context
533537 window = get_window ()
534538 ctx = window .ctx
535-
536539 program = ctx .shape_rectangle_filled_unbuffered_program
537540 geometry = ctx .shape_rectangle_filled_unbuffered_geometry
538541 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 ) )
546549
547550 # Resize buffer
548- data_size = len ( point_list ) * 8
551+ data_size = num_points * 8
549552 # if data_size > buffer.size:
550553 buffer .orphan (size = data_size )
551554
555+ # Pass data to shader
552556 program ['color' ] = color_normalized
553557 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
555561 geometry .render (program , mode = ctx .POINTS , vertices = data_size // 8 )
556562
557563
@@ -585,22 +591,29 @@ def draw_polygon_outline(point_list: PointList,
585591 :py:class:`~arcade.types.Color` instance.
586592 :param line_width: Width of the line in pixels.
587593 """
594+ # Convert to modifiable list & close the loop
588595 new_point_list = list (point_list )
589596 new_point_list .append (point_list [0 ])
590597
598+ # Create a place to store the triangles we'll use to thicken the line
591599 triangle_point_list = []
600+
592601 # This needs a lot of improvement
593602 last_point = None
594603 for point in new_point_list :
595604 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 )
597607 reordered_points = points [1 ], points [0 ], points [2 ], points [3 ]
608+
598609 triangle_point_list .extend (reordered_points )
599610 last_point = point
600611
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 )
603615 triangle_point_list .append (points [1 ])
616+
604617 _generic_draw_line_strip (triangle_point_list , color , gl .GL_TRIANGLE_STRIP )
605618
606619
@@ -875,24 +888,22 @@ def draw_rectangle_filled(center_x: float, center_y: float, width: float,
875888 :py:class:`tuple` or :py:class`~arcade.types.Color` instance.
876889 :param tilt_angle: rotation of the rectangle (clockwise). Defaults to zero.
877890 """
891+ # Fail if we don't have a window, context, or right GL abstractions
878892 window = get_window ()
879893 ctx = window .ctx
880-
881894 program = ctx .shape_rectangle_filled_unbuffered_program
882895 geometry = ctx .shape_rectangle_filled_unbuffered_geometry
883896 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" )
891897
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
892902 program ['color' ] = color_normalized
893903 program ['shape' ] = width , height , tilt_angle
894904 buffer .orphan ()
895905 buffer .write (data = array .array ('f' , (center_x , center_y )))
906+
896907 geometry .render (program , mode = ctx .POINTS , vertices = 1 )
897908
898909
0 commit comments