From 9307deac60876b1e97961bae8736c6f1dff402bf Mon Sep 17 00:00:00 2001 From: Einar Forselv Date: Sun, 30 Jun 2024 08:44:21 +0200 Subject: [PATCH] Remove sprite texture draw (#2161) * Remove draw functions for sprite and texture. * Fix full_screen_example * Fix net_process_animal_facts example * Fix drawing_primitives * remove debug print * Fix gui surface * fix light_demo * fix background_blending * fix background_groups example * fix background_parallax * Fix background_scrolling * fix background_stationary * Always enable alpha blending for background images * Fix sprite properties example * Fix sprite_rooms.py example * Fix dual_stick_shooter * Fix particle_systems * Fix minimap * Fix sprite_animated_keyframes * Fix sprite_collect_coins_background * Fix sprite_collect_coins_diff_levels * Fix unit tests * fix sprite_collect_coins_background --- arcade/__init__.py | 12 +- arcade/context.py | 11 +- arcade/draw/__init__.py | 14 +- arcade/draw/rect.py | 202 ++++++++---------- arcade/examples/background_blending.py | 2 +- arcade/examples/background_groups.py | 5 +- arcade/examples/background_parallax.py | 3 +- arcade/examples/background_scrolling.py | 2 +- arcade/examples/background_stationary.py | 2 +- arcade/examples/drawing_primitives.py | 4 +- arcade/examples/dual_stick_shooter.py | 2 +- arcade/examples/full_screen_example.py | 7 +- arcade/examples/minimap.py | 2 +- arcade/examples/net_process_animal_facts.py | 15 +- arcade/examples/particle_systems.py | 2 +- arcade/examples/sprite_animated_keyframes.py | 2 +- .../sprite_collect_coins_background.py | 42 ++-- .../sprite_collect_coins_diff_levels.py | 24 +-- arcade/examples/sprite_properties.py | 4 +- arcade/examples/sprite_rooms.py | 7 +- arcade/experimental/background/background.py | 8 +- arcade/experimental/light_demo.py | 5 +- arcade/gui/surface.py | 11 +- .../sprite_list_geometry_no_cull_geo.glsl | 4 +- .../shaders/sprites/sprite_single_vs.glsl | 23 ++ arcade/sprite/sprite.py | 37 ---- arcade/texture/texture.py | 116 +--------- arcade/texture_atlas/atlas_default.py | 2 +- .../drawing_support/test_textured_rects.py | 49 ----- tests/unit/sprite/test_sprite_render.py | 2 +- .../texture/test_texture_transform_render.py | 2 +- tests/unit/texture/test_textures.py | 1 - 32 files changed, 209 insertions(+), 415 deletions(-) create mode 100644 arcade/resources/system/shaders/sprites/sprite_single_vs.glsl delete mode 100644 tests/unit/drawing_support/test_textured_rects.py diff --git a/arcade/__init__.py b/arcade/__init__.py index 6793ca180..8e085629d 100644 --- a/arcade/__init__.py +++ b/arcade/__init__.py @@ -122,7 +122,6 @@ def configure_logging(level: Optional[int] = None): from .draw import draw_lines from .draw import draw_lrbt_rectangle_filled from .draw import draw_lrbt_rectangle_outline -from .draw import draw_lbwh_rectangle_textured from .draw import draw_parabola_filled from .draw import draw_parabola_outline from .draw import draw_point @@ -131,8 +130,9 @@ def configure_logging(level: Optional[int] = None): from .draw import draw_polygon_outline from .draw import draw_rect_filled from .draw import draw_rect_outline -from .draw import draw_scaled_texture_rectangle -from .draw import draw_texture_rectangle +from .draw import draw_texture_rect +from .draw import draw_sprite +from .draw import draw_sprite_rect from .draw import draw_triangle_filled from .draw import draw_triangle_outline from .draw import draw_lbwh_rectangle_filled @@ -312,7 +312,6 @@ def configure_logging(level: Optional[int] = None): "draw_line", "draw_line_strip", "draw_lines", - "draw_lbwh_rectangle_textured", "draw_lrbt_rectangle_filled", "draw_lrbt_rectangle_filled", "draw_lrbt_rectangle_outline", @@ -325,9 +324,10 @@ def configure_logging(level: Optional[int] = None): "draw_polygon_outline", "draw_rect_filled", "draw_rect_outline", - "draw_scaled_texture_rectangle", "draw_text", - "draw_texture_rectangle", + "draw_texture_rect", + "draw_sprite", + "draw_sprite_rect", "draw_triangle_filled", "draw_triangle_outline", "draw_lbwh_rectangle_filled", diff --git a/arcade/context.py b/arcade/context.py index 24f519d27..03688a63c 100644 --- a/arcade/context.py +++ b/arcade/context.py @@ -95,6 +95,15 @@ def __init__( self.sprite_list_program_cull["sprite_texture"] = 0 self.sprite_list_program_cull["uv_texture"] = 1 + self.sprite_program_single = self.load_program( + vertex_shader=":system:shaders/sprites/sprite_single_vs.glsl", + geometry_shader=":system:shaders/sprites/sprite_list_geometry_no_cull_geo.glsl", + fragment_shader=":system:shaders/sprites/sprite_list_geometry_fs.glsl", + ) + self.sprite_program_single["sprite_texture"] = 0 + self.sprite_program_single["uv_texture"] = 1 + self.sprite_program_single["spritelist_color"] = 1.0, 1.0, 1.0, 1.0 + # Shapes self.shape_line_program: Program = self.load_program( vertex_shader=":system:shaders/shapes/line/unbuffered_vs.glsl", @@ -185,7 +194,7 @@ def __init__( self.shape_rectangle_filled_unbuffered_geometry: Geometry = self.geometry( [BufferDescription(self.shape_rectangle_filled_unbuffered_buffer, "2f", ["in_vert"])] ) - self.atlas_geometry: Geometry = self.geometry() + self.geometry_empty: Geometry = self.geometry() self._atlas: Optional[TextureAtlasBase] = None # Global labels we modify in `arcade.draw_text`. diff --git a/arcade/draw/__init__.py b/arcade/draw/__init__.py index f69902659..d3a78011b 100644 --- a/arcade/draw/__init__.py +++ b/arcade/draw/__init__.py @@ -28,10 +28,9 @@ draw_rect_filled, draw_rect_outline_kwargs, draw_rect_filled_kwargs, - draw_scaled_texture_rectangle, - draw_texture_rectangle, - # draw_texture_rect - draw_lbwh_rectangle_textured, + draw_texture_rect, + draw_sprite, + draw_sprite_rect, ) from .helpers import get_points_for_thick_line from .screenshot import get_pixel, get_image @@ -70,10 +69,9 @@ "draw_rect_filled", "draw_rect_outline_kwargs", "draw_rect_filled_kwargs", - "draw_scaled_texture_rectangle", - "draw_texture_rectangle", - # draw_texture_rect - "draw_lbwh_rectangle_textured", + "draw_texture_rect", + "draw_sprite", + "draw_sprite_rect", # helpers "get_points_for_thick_line", # screenshot diff --git a/arcade/draw/rect.py b/arcade/draw/rect.py index 596a87118..a99119838 100644 --- a/arcade/draw/rect.py +++ b/arcade/draw/rect.py @@ -2,13 +2,100 @@ from arcade import gl from arcade.math import rotate_point -from arcade.types import RGBA255, PointList, AsFloat, Rect, LRBT, LBWH, Color +from arcade.types import RGBA255, PointList, AsFloat, Rect, LRBT, LBWH, XYWH, Color from arcade.texture import Texture +from arcade.sprite import BasicSprite from arcade.window_commands import get_window from .helpers import _generic_draw_line_strip from arcade.color import WHITE +def draw_texture_rect( + texture: Texture, + rect: Rect, + *, + color: Color = WHITE, + angle=0.0, + blend=True, + alpha=1.0, + pixelated=False, +) -> None: + """ + Draw a texture on a rectangle. + + :param texture: identifier of texture returned from load_texture() call + :param rect: Rectangle to draw the texture on. + :param color: Color of the texture. Defaults to white. + :param angle: Rotation of the texture in degrees. Defaults to zero. + :param blend: If True, enable alpha blending. Defaults to True. + :param alpha: Transparency of image. 0.0 is fully transparent, 1.0 (default) is visible. + """ + ctx = get_window().ctx + if blend: + ctx.enable(ctx.BLEND) + + atlas = ctx.default_atlas + + texture_id, _ = ctx.default_atlas.add(texture) + if pixelated: + atlas.texture.filter = gl.NEAREST, gl.NEAREST + else: + atlas.texture.filter = gl.LINEAR, gl.LINEAR + + atlas.texture.use(unit=0) + atlas.use_uv_texture(unit=1) + + geometry = ctx.geometry_empty + program = ctx.sprite_program_single + program["pos"] = rect.center_x, rect.center_y, 0 + program["color"] = color.normalized + program["size"] = rect.width, rect.height + program["angle"] = angle + program["texture_id"] = float(texture_id) + program["spritelist_color"] = 1.0, 1.0, 1.0, alpha + + geometry.render(program, mode=gl.POINTS, vertices=1) + + # if blend: + # ctx.disable(ctx.BLEND) + + +def draw_sprite(sprite: BasicSprite, *, blend: bool = True, alpha=1.0, pixelated=False) -> None: + """ + Draw a sprite. + + :param sprite: The sprite to draw. + """ + draw_texture_rect( + sprite.texture, + rect=XYWH(sprite.center_x, sprite.center_y, sprite.width, sprite.height), + color=sprite.color, + angle=sprite._angle, + blend=blend, + alpha=alpha, + pixelated=pixelated, + ) + + +def draw_sprite_rect( + sprite: BasicSprite, rect: Rect, *, blend: bool = True, alpha=1.0, pixelated=False +) -> None: + """ + Draw a sprite. + + :param sprite: The sprite to draw. + """ + draw_texture_rect( + sprite.texture, + rect=rect, + color=sprite.color, + angle=sprite._angle, + blend=blend, + alpha=alpha, + pixelated=pixelated, + ) + + def draw_lrbt_rectangle_outline( left: float, right: float, @@ -102,119 +189,6 @@ def draw_lbwh_rectangle_filled( draw_rect_filled(LBWH(left, bottom, width, height), color) -def draw_scaled_texture_rectangle( - center_x: float, - center_y: float, - texture: Texture, - scale: float = 1.0, - angle: float = 0, - alpha: int = 255, -) -> None: - """ - Draw a textured rectangle on-screen. - - .. warning:: This method can be slow! - - Most users should consider using - :py:class:`arcade.Sprite` with - :py:class:`arcade.SpriteList` instead of this - function. - - OpenGL accelerates drawing by using batches to draw multiple things - at once. This method doesn't do that. - - If you need finer control or less overhead than arcade allows, - consider `pyglet's batching features - `_. - - :param center_x: x coordinate of rectangle center. - :param center_y: y coordinate of rectangle center. - :param texture: identifier of texture returned from - load_texture() call - :param scale: scale of texture - :param angle: rotation of the rectangle (clockwise). Defaults to zero. - :param alpha: Transparency of image. 0 is fully transparent, - 255 (default) is fully visible - """ - texture.draw_scaled(center_x, center_y, scale, angle, alpha) - - -def draw_texture_rectangle( - center_x: float, - center_y: float, - width: float, - height: float, - texture: Texture, - angle: float = 0, - alpha: int = 255, -) -> None: - """ - Draw a textured rectangle on-screen. - - :param center_x: x coordinate of rectangle center. - :param center_y: y coordinate of rectangle center. - :param width: width of texture - :param height: height of texture - :param texture: identifier of texture returned from load_texture() call - :param angle: rotation of the rectangle. Defaults to zero (clockwise). - :param alpha: Transparency of image. 0 is fully transparent, 255 (default) is visible - """ - texture.draw_sized(center_x, center_y, width, height, angle, alpha) - - -# def draw_texture_rect(texture: Texture, rect: Rect, blend=True) -> None: -# """ -# Draw a texture on a rectangle. - -# :param texture: identifier of texture returned from load_texture() call -# :param rect: Rectangle to draw the texture on. -# """ -# ctx = get_window().ctx -# if blend: -# ctx.enable(ctx.BLEND) - -# texture_id, region = ctx.default_atlas.add(texture) - -# ctx.default_atlas.use_uv_texture(unit=0) -# program = None # texture program -# # program["texture"] = 0 -# # program["alpha"] = 1.0 -# geometry = None # texture geometry -# # geometry.render(program, mode=gl.GL_TRIANGLE_STRIP, vertices=4) - -# if blend: -# ctx.disable(ctx.BLEND) - - -def draw_lbwh_rectangle_textured( - left: float, - bottom: float, - width: float, - height: float, - texture: Texture, - angle: float = 0, - alpha: int = 255, -) -> None: - """ - Draw a texture extending from bottom left to top right. - - :param left: The x coordinate of the left edge of the rectangle. - :param bottom: The y coordinate of the bottom of the rectangle. - :param width: The width of the rectangle. - :param height: The height of the rectangle. - :param texture: identifier of texture returned from load_texture() call - :param angle: rotation of the rectangle. Defaults to zero (clockwise). - :param alpha: Transparency of image. 0 is fully transparent, 255 (default) is visible - """ - - center_x = left + (width / 2) - center_y = bottom + (height / 2) - texture.draw_sized(center_x, center_y, width, height, angle=angle, alpha=alpha) - - -# Reference implementations: drawing of new Rect - - def draw_rect_outline( rect: Rect, color: RGBA255, border_width: float = 1, tilt_angle: float = 0 ) -> None: diff --git a/arcade/examples/background_blending.py b/arcade/examples/background_blending.py index 6414c3440..3b52fc0ea 100644 --- a/arcade/examples/background_blending.py +++ b/arcade/examples/background_blending.py @@ -97,7 +97,7 @@ def on_draw(self): self.background_1.draw() self.background_2.draw() - self.player_sprite.draw() + arcade.draw_sprite(self.player_sprite) def on_key_press(self, symbol: int, modifiers: int): if symbol in (arcade.key.LEFT, arcade.key.A): diff --git a/arcade/examples/background_groups.py b/arcade/examples/background_groups.py index 470ca1e36..9a7892699 100644 --- a/arcade/examples/background_groups.py +++ b/arcade/examples/background_groups.py @@ -97,8 +97,11 @@ def on_draw(self): self.camera.use() + self.ctx.enable(self.ctx.BLEND) self.backgrounds.draw() - self.player_sprite.draw() + self.ctx.disable(self.ctx.BLEND) + + arcade.draw_sprite(self.player_sprite) def on_key_press(self, symbol: int, modifiers: int): # Support arrow keys and ASWD diff --git a/arcade/examples/background_parallax.py b/arcade/examples/background_parallax.py index af59fc173..28b537a9d 100644 --- a/arcade/examples/background_parallax.py +++ b/arcade/examples/background_parallax.py @@ -114,8 +114,9 @@ def on_draw(self): bg.pos = self.camera.bottom_left # Follow the car to fake infinity # Draw the background & the player's car + self.ctx.enable(self.ctx.BLEND) bg.draw() - self.player_sprite.draw(pixelated=True) + arcade.draw_sprite(self.player_sprite, pixelated=True) def update_car_direction(self): """ diff --git a/arcade/examples/background_scrolling.py b/arcade/examples/background_scrolling.py index 5f3b98ef9..078b0a5f7 100644 --- a/arcade/examples/background_scrolling.py +++ b/arcade/examples/background_scrolling.py @@ -68,7 +68,7 @@ def on_draw(self): self.background.texture.offset = self.camera.bottom_left self.background.draw() - self.player_sprite.draw() + arcade.draw_sprite(self.player_sprite) def on_key_press(self, symbol: int, modifiers: int): if symbol in (arcade.key.LEFT, arcade.key.A): diff --git a/arcade/examples/background_stationary.py b/arcade/examples/background_stationary.py index d33759e21..f6a67d892 100644 --- a/arcade/examples/background_stationary.py +++ b/arcade/examples/background_stationary.py @@ -74,7 +74,7 @@ def on_draw(self): self.camera.use() self.background.draw() - self.player_sprite.draw() + arcade.draw_sprite(self.player_sprite) def on_key_press(self, symbol: int, modifiers: int): if symbol in (arcade.key.LEFT, arcade.key.A): diff --git a/arcade/examples/drawing_primitives.py b/arcade/examples/drawing_primitives.py index e67576988..682c2bc19 100644 --- a/arcade/examples/drawing_primitives.py +++ b/arcade/examples/drawing_primitives.py @@ -146,8 +146,8 @@ arcade.draw_text("draw_bitmap", 483, 3, arcade.color.BLACK, 12) texture = arcade.load_texture(":resources:images/space_shooter/playerShip1_orange.png") scale = .6 -arcade.draw_scaled_texture_rectangle(540, 120, texture, scale, 0) -arcade.draw_scaled_texture_rectangle(540, 60, texture, scale, 45) +arcade.draw_texture_rect(texture, arcade.XYWH(540, 120, texture.width, texture.height).scale(scale)) +arcade.draw_texture_rect(texture, arcade.XYWH(540, 60, texture.width, texture.height).scale(scale), angle=45) # Finish the render. # Nothing will be drawn without this. diff --git a/arcade/examples/dual_stick_shooter.py b/arcade/examples/dual_stick_shooter.py index f77770721..3869634e8 100644 --- a/arcade/examples/dual_stick_shooter.py +++ b/arcade/examples/dual_stick_shooter.py @@ -323,7 +323,7 @@ def on_draw(self): # draw game items self.bullet_list.draw() self.enemy_list.draw() - self.player.draw() + arcade.draw_sprite(self.player) # Put the score on the screen. output = f"Score: {self.score}" diff --git a/arcade/examples/full_screen_example.py b/arcade/examples/full_screen_example.py index d7ae4b486..0351ccfe1 100644 --- a/arcade/examples/full_screen_example.py +++ b/arcade/examples/full_screen_example.py @@ -56,12 +56,12 @@ def on_draw(self): self.camera.use() self.camera.position = 0, 0 # Draw some boxes on the bottom so we can see how they change - for count in range(100): + for count in range(20): x = count * 128 y = count * 128 width = 128 height = 128 - arcade.draw_texture_rectangle(x, y, width, height, self.example_image) + arcade.draw_texture_rect(self.example_image, arcade.XYWH(x, y, width, height)) arcade.draw_rect_outline(LRBT(0, SCREEN_WIDTH, 0, SCREEN_HEIGHT), arcade.color.WHITE, 5) @@ -95,6 +95,9 @@ def on_key_press(self, key, modifiers): self.camera.projection = LRBT(left=0, right=SCREEN_WIDTH, bottom=0, top=SCREEN_HEIGHT) self.camera.viewport = LRBT(left=0, right=self.width, bottom=0, top=self.height) + if key == arcade.key.ESCAPE: + self.close() + def main(): """ Main function """ diff --git a/arcade/examples/minimap.py b/arcade/examples/minimap.py index 26ea09efc..54dfe657b 100644 --- a/arcade/examples/minimap.py +++ b/arcade/examples/minimap.py @@ -111,7 +111,7 @@ def update_minimap(self): with self.minimap_sprite_list.atlas.render_into(self.minimap_texture, projection=proj) as fbo: fbo.clear(color=MINIMAP_BACKGROUND_COLOR) self.wall_list.draw() - self.player_sprite.draw() + arcade.draw_sprite(self.player_sprite) def on_draw(self): """ diff --git a/arcade/examples/net_process_animal_facts.py b/arcade/examples/net_process_animal_facts.py index 7ea2c450a..9a41c3ef3 100644 --- a/arcade/examples/net_process_animal_facts.py +++ b/arcade/examples/net_process_animal_facts.py @@ -73,9 +73,9 @@ def on_draw(self): # Draw a background image fading between two images if needed fade = clamp(time.time() - self.bg_updated_time, 0.0, 1.0) - self.draw_background(self.bg_texture_1, int(80 * fade)) + self.draw_background(self.bg_texture_1, fade * 0.35) if fade < 1.0: - self.draw_background(self.bg_texture_2, int(80 * (1.0 - fade))) + self.draw_background(self.bg_texture_2, 0.35 * (1.0 - fade)) # Draw the fact text self.text_fact.draw() @@ -105,13 +105,12 @@ def draw_background(self, texture: arcade.Texture, alpha: int) -> None: if texture is None: return - # Get the higest ratio of width or height to fill the window + # Get the highest ratio of width or height to fill the window scale = max(self.window.width / texture.width, self.window.height / texture.height) - texture.draw_sized( - center_x=self.window.width / 2, - center_y=self.window.height / 2, - width=texture.width * scale, - height=texture.height * scale, + arcade.draw_texture_rect( + texture, + arcade.XYWH(self.window.width / 2, self.window.height / 2, texture.width * scale, texture.height * scale), + blend=True, alpha=alpha, ) diff --git a/arcade/examples/particle_systems.py b/arcade/examples/particle_systems.py index 9f9690361..526b96e57 100644 --- a/arcade/examples/particle_systems.py +++ b/arcade/examples/particle_systems.py @@ -751,7 +751,7 @@ def on_update(self, delta_time): def on_draw(self): self.clear() - self.obj.draw() + arcade.draw_sprite(self.obj) if self.label: arcade.draw_text("#{} {}".format(self.emitter_factory_id, self.label), SCREEN_WIDTH / 2, SCREEN_HEIGHT - 25, diff --git a/arcade/examples/sprite_animated_keyframes.py b/arcade/examples/sprite_animated_keyframes.py index f7776c02f..8c7c55351 100644 --- a/arcade/examples/sprite_animated_keyframes.py +++ b/arcade/examples/sprite_animated_keyframes.py @@ -33,7 +33,7 @@ def __init__(self): def on_draw(self): self.clear() - self.sprite.draw(pixelated=True) + arcade.draw_sprite(self.sprite, pixelated=True) def on_update(self, delta_time: float): self.sprite.update_animation(delta_time) diff --git a/arcade/examples/sprite_collect_coins_background.py b/arcade/examples/sprite_collect_coins_background.py index 1d188aadd..ac4dabe2a 100644 --- a/arcade/examples/sprite_collect_coins_background.py +++ b/arcade/examples/sprite_collect_coins_background.py @@ -31,14 +31,18 @@ def __init__(self, width, height, title): super().__init__(width, height, title) # Background image will be stored in this variable - self.background = None + # Image from: + # https://wallpaper-gallery.net/single/free-background-images/free-background-images-22.html + self.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg") # Variables that will hold sprite lists - self.player_list = None - self.coin_list = None + self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", + scale=PLAYER_SCALING) + self.player_list = arcade.SpriteList() + self.player_list.append(self.player_sprite) + self.coin_list = arcade.SpriteList() # Set up the player info - self.player_sprite = None self.score = 0 self.score_text = arcade.Text("Score: 0", 10, 20, arcade.color.WHITE, 14) @@ -48,29 +52,17 @@ def __init__(self, width, height, title): # Set the background color self.background_color = arcade.color.AMAZON - # Load the background image. Do this in the setup so we don't keep reloading it all the time. - # Image from: - # https://wallpaper-gallery.net/single/free-background-images/free-background-images-22.html - self.background = arcade.load_texture(":resources:images/backgrounds/abstract_1.jpg") - - def setup(self): - """ Set up the game and initialize the variables. """ - - + def reset(self): + """Restart the game.""" # Sprite lists - self.player_list = arcade.SpriteList() - self.coin_list = arcade.SpriteList() + self.coin_list.clear() # Set up the player self.score = 0 - self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", - scale=PLAYER_SCALING) self.player_sprite.center_x = 50 self.player_sprite.center_y = 50 - self.player_list.append(self.player_sprite) for i in range(50): - # Create the coin instance coin = arcade.Sprite(":resources:images/items/coinGold.png", scale=COIN_SCALING) @@ -90,9 +82,7 @@ def on_draw(self): self.clear() # Draw the background texture - arcade.draw_lbwh_rectangle_textured(0, 0, - SCREEN_WIDTH, SCREEN_HEIGHT, - self.background) + arcade.draw_texture_rect(self.background, arcade.LBWH(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)) # Draw all the sprites. self.coin_list.draw() @@ -124,11 +114,17 @@ def on_update(self, delta_time): coin.remove_from_sprite_lists() self.score += 1 + def on_key_press(self, symbol: int, modifiers: int): + if symbol == arcade.key.R: + self.reset() + elif symbol == arcade.key.ESCAPE: + self.close() + def main(): """ Main function """ window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) - window.setup() + window.reset() arcade.run() diff --git a/arcade/examples/sprite_collect_coins_diff_levels.py b/arcade/examples/sprite_collect_coins_diff_levels.py index b7d275e7c..3206fba8e 100644 --- a/arcade/examples/sprite_collect_coins_diff_levels.py +++ b/arcade/examples/sprite_collect_coins_diff_levels.py @@ -59,13 +59,16 @@ def __init__(self, width, height, title): super().__init__(width, height, title) # Variables that will hold sprite lists - self.player_list = None - self.coin_list = None + self.player_list = arcade.SpriteList() + self.coin_list = arcade.SpriteList() # Set up the player info - self.player_sprite = None - self.score = 0 + # Set up the player + self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", + scale=SPRITE_SCALING) + self.player_list.append(self.player_sprite) + self.score = 0 self.level = 1 # Don't show the mouse cursor @@ -113,22 +116,17 @@ def level_3(self): # Add the coin to the lists self.coin_list.append(coin) - def setup(self): + def reset(self): """ Set up the game and initialize the variables. """ self.score = 0 self.level = 1 # Sprite lists - self.player_list = arcade.SpriteList() - self.coin_list = arcade.SpriteList() + self.coin_list.clear() - # Set up the player - self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", - scale=SPRITE_SCALING) self.player_sprite.center_x = 50 self.player_sprite.center_y = 50 - self.player_list.append(self.player_sprite) self.level_1() @@ -141,7 +139,7 @@ def on_draw(self): self.clear() # Draw all the sprites. - self.player_sprite.draw() + arcade.draw_sprite(self.player_sprite) self.coin_list.draw() # Put the text on the screen. @@ -186,7 +184,7 @@ def on_update(self, delta_time): def main(): """ Main function """ window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE) - window.setup() + window.reset() arcade.run() diff --git a/arcade/examples/sprite_properties.py b/arcade/examples/sprite_properties.py index 74775f29e..00015ea25 100644 --- a/arcade/examples/sprite_properties.py +++ b/arcade/examples/sprite_properties.py @@ -51,7 +51,7 @@ def setup(self): # Set up the player # Character image from kenney.nl self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png", - scale=SPRITE_SCALING_PLAYER) + scale=0.75) self.player_sprite.center_x = 50 self.player_sprite.center_y = 150 self.player_list.append(self.player_sprite) @@ -71,7 +71,7 @@ def on_draw(self): """ Draw everything """ self.clear() self.coin_list.draw() - self.trigger_sprite.draw() + arcade.draw_sprite(self.trigger_sprite) self.player_list.draw() # Put the instructions on the screen. diff --git a/arcade/examples/sprite_rooms.py b/arcade/examples/sprite_rooms.py index cc143f254..3e0edf183 100644 --- a/arcade/examples/sprite_rooms.py +++ b/arcade/examples/sprite_rooms.py @@ -172,9 +172,10 @@ def on_draw(self): self.clear() # Draw the background texture - arcade.draw_lbwh_rectangle_textured(0, 0, - SCREEN_WIDTH, SCREEN_HEIGHT, - self.rooms[self.current_room].background) + arcade.draw_texture_rect( + self.rooms[self.current_room].background, + rect=arcade.LBWH(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), + ) # Draw all the walls in this room self.rooms[self.current_room].wall_list.draw() diff --git a/arcade/experimental/background/background.py b/arcade/experimental/background/background.py index 35e6a6715..1a77dbde2 100644 --- a/arcade/experimental/background/background.py +++ b/arcade/experimental/background/background.py @@ -212,13 +212,9 @@ def draw(self, shift: tuple[float, float] = (0.0, 0.0)): "Attempting to set uniform 'pos' when the shader does not have a uniform with that name." ) - if self.blend < 1.0: - self._ctx.enable(self._ctx.BLEND) - self.texture.use(0) - self.geometry.render(self.shader) - - self._ctx.disable(self._ctx.BLEND) + with self._ctx.enabled(self._ctx.BLEND): + self.geometry.render(self.shader) def blend_layer(self, other, percent: float): self.blend = 1 - percent diff --git a/arcade/experimental/light_demo.py b/arcade/experimental/light_demo.py index dd2ffce99..ab3efa433 100644 --- a/arcade/experimental/light_demo.py +++ b/arcade/experimental/light_demo.py @@ -2,7 +2,6 @@ import math import arcade -from arcade.draw import draw_lbwh_rectangle_textured from arcade.experimental.lights import Light, LightLayer # Do the math to figure out our screen dimensions @@ -75,7 +74,9 @@ def on_draw(self): # Everything that should be affected by lights in here with self.light_layer: - draw_lbwh_rectangle_textured(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, self.background) + arcade.draw_texture_rect( + self.background, arcade.LBWH(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) + ) self.torch_list.draw() # Draw the contents with lighting diff --git a/arcade/gui/surface.py b/arcade/gui/surface.py index 1f160afda..19e0f2254 100644 --- a/arcade/gui/surface.py +++ b/arcade/gui/surface.py @@ -7,7 +7,6 @@ from arcade import Texture from arcade.camera import OrthographicProjector, OrthographicProjectionData, CameraData from arcade.color import TRANSPARENT_BLACK -from arcade.draw import draw_lbwh_rectangle_textured from arcade.gl import Framebuffer from arcade.gui.nine_patch import NinePatchTexture from arcade.types import RGBA255, Point @@ -121,15 +120,7 @@ def draw_texture( tex.draw_sized(size=(width, height)) else: - draw_lbwh_rectangle_textured( - left=x, - bottom=y, - width=width, - height=height, - texture=tex, - angle=angle, - alpha=alpha, - ) + arcade.draw_texture_rect(tex, LBWH(x, y, width, height), angle=angle, alpha=alpha) def draw_sprite(self, x, y, width, height, sprite): """Draw a sprite to the surface""" diff --git a/arcade/resources/system/shaders/sprites/sprite_list_geometry_no_cull_geo.glsl b/arcade/resources/system/shaders/sprites/sprite_list_geometry_no_cull_geo.glsl index 1a114ebe9..f03d81ef7 100644 --- a/arcade/resources/system/shaders/sprites/sprite_list_geometry_no_cull_geo.glsl +++ b/arcade/resources/system/shaders/sprites/sprite_list_geometry_no_cull_geo.glsl @@ -26,8 +26,8 @@ void main() { vec2 hsize = v_size[0] / 2.0; float angle = radians(v_angle[0]); mat2 rot = mat2( - cos(angle), -sin(angle), - sin(angle), cos(angle) + cos(angle), -sin(angle), + sin(angle), cos(angle) ); mat4 mvp = window.projection * window.view; // Emit a quad with the right position, rotation and texture coordinates diff --git a/arcade/resources/system/shaders/sprites/sprite_single_vs.glsl b/arcade/resources/system/shaders/sprites/sprite_single_vs.glsl new file mode 100644 index 000000000..d203f4c2e --- /dev/null +++ b/arcade/resources/system/shaders/sprites/sprite_single_vs.glsl @@ -0,0 +1,23 @@ +#version 330 +// Rendering a simple sprite or texture from uniforms because +// we want to avoid having to allocate a buffer for each sprite + +uniform vec3 pos; +uniform vec2 size; +uniform vec4 color; +uniform float angle; +uniform float texture_id; + +out vec2 v_size; +out vec4 v_color; +out float v_angle; +out float v_texture; + +void main() +{ + gl_Position = vec4(pos, 1.0); + v_size = size; + v_color = color; + v_angle = angle; + v_texture = texture_id; +} diff --git a/arcade/sprite/sprite.py b/arcade/sprite/sprite.py index 0c0a7b334..17cb70c82 100644 --- a/arcade/sprite/sprite.py +++ b/arcade/sprite/sprite.py @@ -9,7 +9,6 @@ from arcade.hitbox import HitBox, RotatableHitBox from arcade.texture import get_default_texture from arcade.types import PathOrTexture, Point2 -from arcade.gl.types import OpenGlFilter, BlendFunction from .base import BasicSprite from .mixins import PymunkMixin @@ -58,7 +57,6 @@ class Sprite(BasicSprite, PymunkMixin): "cur_texture_index", "_hit_box", "physics_engines", - "_sprite_list", "guid", "force", ) @@ -312,41 +310,6 @@ def stop(self) -> None: self.velocity = 0, 0 self.change_angle = 0 - # ---- Draw Methods ---- - - def draw( - self, - *, - filter: Optional[OpenGlFilter] = None, - pixelated: Optional[bool] = None, - blend_function: Optional[BlendFunction] = None, - ) -> None: - """ - A debug method which draws the sprite into the current OpenGL context. - - .. warning:: You are probably looking for :py:meth:`SpriteList.draw() `! - - Drawing individual sprites is slow compared to using :py:class:`~arcade.SpriteList`. - See :ref:`pg_spritelists_why` for more information. - - This method should not be relied on. It may be removed one day. - - :param filter: Optional parameter to set OpenGL filter, such as - `gl.GL_NEAREST` to avoid smoothing. - :param pixelated: ``True`` for pixelated and ``False`` for smooth interpolation. - Shortcut for setting filter=GL_NEAREST. - :param blend_function: Optional parameter to set the OpenGL blend function used for drawing the sprite list, - such as 'arcade.Window.ctx.BLEND_ADDITIVE' or 'arcade.Window.ctx.BLEND_DEFAULT' - """ - if self._sprite_list is None: - from arcade import SpriteList - - self._sprite_list = SpriteList(capacity=1) - - self._sprite_list.append(self) - self._sprite_list.draw(filter=filter, pixelated=pixelated, blend_function=blend_function) - self._sprite_list.remove(self) - # ----Update Methods ---- def update(self) -> None: diff --git a/arcade/texture/texture.py b/arcade/texture/texture.py index b3bbdc9d6..276376392 100644 --- a/arcade/texture/texture.py +++ b/arcade/texture/texture.py @@ -2,7 +2,7 @@ import hashlib import logging -from typing import Any, Optional, Type, Union, TYPE_CHECKING +from typing import Any, Optional, Type, Union from pathlib import Path import PIL.Image @@ -25,10 +25,8 @@ ) from arcade.types import RGBA255, Point2List -from arcade.types.rect import Rect -if TYPE_CHECKING: - from arcade.sprite_list import SpriteList +# from arcade.types.rect import Rect __all__ = ["ImageData", "Texture"] @@ -133,7 +131,6 @@ class Texture: "_size", "_vertex_order", "_transforms", - "_sprite_list", "_hit_box_algorithm", "_hit_box_points", "_hash", @@ -173,9 +170,6 @@ def __init__( # texture is flipped or rotated. self._vertex_order = 0, 1, 2, 3 - # Internal spritelist for drawing - self._sprite_list: Optional[SpriteList] = None - self._hit_box_algorithm = hit_box_algorithm or hitbox.algo_default if not isinstance(self._hit_box_algorithm, HitBoxAlgorithm): raise TypeError( @@ -720,109 +714,3 @@ def _calculate_hit_box_points(self) -> Point2List: or when the hit box points are requested the first time. """ return self._hit_box_algorithm.calculate(self.image) - - # ----- Drawing functions ----- - - def _create_cached_spritelist(self) -> "SpriteList": - """Create or return the cached sprite list.""" - from arcade.sprite_list import SpriteList - - if self._sprite_list is None: - self._sprite_list = SpriteList(capacity=1) - return self._sprite_list - - def draw_sized( - self, - center_x: float, - center_y: float, - width: float, - height: float, - angle: float = 0.0, - alpha: int = 255, - ): - """ - Draw a texture with a specific width and height. - - .. warning:: This is a very slow method of drawing a texture, - and should be used sparingly. The method simply - creates a sprite internally and draws it. - - :param center_x: X position to draw texture - :param center_y: Y position to draw texture - :param width: Width to draw texture - :param height: Height to draw texture - :param angle: Angle to draw texture - :param alpha: Alpha value to draw texture - """ - from arcade import Sprite - - spritelist = self._create_cached_spritelist() - sprite = Sprite( - self, - center_x=center_x, - center_y=center_y, - angle=angle, - ) - # sprite.size = (width, height) - sprite.width = width - sprite.height = height - - sprite.alpha = alpha - # Due to circular references we can't keep the sprite around - spritelist.append(sprite) - spritelist.draw() - spritelist.remove(sprite) - - def draw_scaled( - self, - center_x: float, - center_y: float, - scale: float = 1.0, - angle: float = 0.0, - alpha: int = 255, - ): - """ - Draw the texture. - - .. warning:: This is a very slow method of drawing a texture, - and should be used sparingly. The method simply - creates a sprite internally and draws it. - - :param center_x: X location of where to draw the texture. - :param center_y: Y location of where to draw the texture. - :param scale: Scale to draw rectangle. Defaults to 1. - :param angle: Angle to rotate the texture by. - :param alpha: The transparency of the texture ``(0-255)``. - """ - from arcade import Sprite - - spritelist = self._create_cached_spritelist() - sprite = Sprite( - self, - center_x=center_x, - center_y=center_y, - angle=angle, - scale=scale, - ) - sprite.alpha = alpha - # Due to circular references we can't keep the sprite around - spritelist.append(sprite) - spritelist.draw() - spritelist.remove(sprite) - - def draw_rect(self, rect: Rect, alpha: int = 255): - """ - Draw the texture. - - .. warning:: This is a very slow method of drawing a texture, - and should be used sparingly. The method simply - creates a sprite internally and draws it. - - :param rect: A Rect to draw this texture to. - :param alpha: The transparency of the texture ``(0-255)``. - """ - self.draw_sized(rect.x, rect.y, rect.width, rect.height, alpha=alpha) - - def __repr__(self) -> str: - cache_name = getattr(self, "cache_name", None) - return f"" diff --git a/arcade/texture_atlas/atlas_default.py b/arcade/texture_atlas/atlas_default.py index 0a2544402..d52e68c55 100644 --- a/arcade/texture_atlas/atlas_default.py +++ b/arcade/texture_atlas/atlas_default.py @@ -671,7 +671,7 @@ def resize(self, size: Tuple[int, int]) -> None: with self._fbo.activate(): # Ensure no context flags are enabled with self._ctx.enabled_only(): - self._ctx.atlas_geometry.render( + self._ctx.geometry_empty.render( self._ctx.atlas_resize_program, mode=self._ctx.POINTS, vertices=self.max_width, diff --git a/tests/unit/drawing_support/test_textured_rects.py b/tests/unit/drawing_support/test_textured_rects.py deleted file mode 100644 index dd1db3372..000000000 --- a/tests/unit/drawing_support/test_textured_rects.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -Tests for textures. -""" -import arcade - - -def test_textured_rects(window: arcade.Window): - window.background_color = arcade.color.AMAZON - texture = arcade.load_texture(":resources:images/space_shooter/playerShip1_orange.png") - - def on_draw(): - arcade.start_render() - scale = .6 - arcade.draw_texture_rectangle( - 540, 120, - texture.image.width * scale, - texture.image.height * scale, - texture, angle=45, - ) - arcade.draw_lbwh_rectangle_textured(10, 400, 64, 64, texture) - - for i in range(15): - arcade.draw_scaled_texture_rectangle( - i * 50 + 20, 220, - texture, - scale, - angle=45, alpha=i * 15, - ) - - window.on_draw = on_draw - window.test() - - -def test_textured_rects_2(window: arcade.Window): - """Draw scaled rects""" - window.background_color = arcade.color.AMAZON - texture = arcade.load_texture(":resources:images/items/coinGold.png") - - def on_draw(): - arcade.start_render() - x = 50 - y = 50 - scale = 1.0 - # assert arcade.get_pixel(50, 50) == (59, 122, 87) - arcade.draw_scaled_texture_rectangle(x, y, texture, scale) - # assert arcade.get_pixel(50, 50) == (255, 204, 0) - - window.on_draw = on_draw - window.test(10) diff --git a/tests/unit/sprite/test_sprite_render.py b/tests/unit/sprite/test_sprite_render.py index 443248683..0ddb05a0a 100644 --- a/tests/unit/sprite/test_sprite_render.py +++ b/tests/unit/sprite/test_sprite_render.py @@ -94,7 +94,7 @@ def on_draw(): assert arcade.get_pixel(150, 50) == (191, 121, 88) assert arcade.get_pixel(230, 230) == (59, 122, 87) - individual_coin.draw() + arcade.draw_sprite(individual_coin) assert arcade.get_pixel(230, 230) == (255, 204, 0) # Test for coin scaling diff --git a/tests/unit/texture/test_texture_transform_render.py b/tests/unit/texture/test_texture_transform_render.py index 0de33d663..45f685efc 100644 --- a/tests/unit/texture/test_texture_transform_render.py +++ b/tests/unit/texture/test_texture_transform_render.py @@ -49,7 +49,7 @@ def test_rotate90_transform(ctx: arcade.ArcadeContext, image, transform, pil_tra with fbo.activate(): fbo.clear() ctx.projection_matrix = Mat4.orthogonal_projection(0, image.width, 0, image.height, -100, 100) - sprite.draw(pixelated=True) + arcade.draw_sprite(sprite, pixelated=True) expected_image = image.transpose(pil_transform) fbo_data = fbo.read(components=4) diff --git a/tests/unit/texture/test_textures.py b/tests/unit/texture/test_textures.py index 121b426ac..75c2f5395 100644 --- a/tests/unit/texture/test_textures.py +++ b/tests/unit/texture/test_textures.py @@ -36,7 +36,6 @@ def test_load_texture(): assert tex.height == 128 assert tex.size == (128, 128) assert tex.hit_box_points is not None - assert tex._sprite_list is None with pytest.raises(FileNotFoundError): arcade.load_texture("moo")