diff --git a/arcade/examples/gl/spritelist_interaction_bouncing_coins.py b/arcade/examples/gl/spritelist_interaction_bouncing_coins.py index 65bf1d1795..d9f38e1d75 100644 --- a/arcade/examples/gl/spritelist_interaction_bouncing_coins.py +++ b/arcade/examples/gl/spritelist_interaction_bouncing_coins.py @@ -15,9 +15,10 @@ from array import array from random import randint, uniform +from typing import cast import arcade -from arcade.gl.types import BufferDescription +from arcade.gl import BufferDescription, Buffer from arcade import hitbox WINDOW_WIDTH = 1280 @@ -32,7 +33,7 @@ def __init__(self): super().__init__(WINDOW_WIDTH, WINDOW_HEIGHT, resizable=True) # Generate lots of coins in random positions - self.coins = arcade.SpriteList(use_spatial_hash=None) + self.coins = arcade.SpriteList(use_spatial_hash=False) texture = arcade.load_texture( ":resources:images/items/coinGold.png", hit_box_algorithm=hitbox.algo_bounding_box, @@ -59,14 +60,14 @@ def __init__(self): uniform float delta_time; uniform vec2 size; - in vec3 in_pos; + in vec4 in_pos_angle; in vec2 in_vel; - out vec3 out_pos; + out vec4 out_pos_angle; out vec2 out_vel; void main() { - vec2 pos = in_pos.xy + in_vel * 100.0 * delta_time; + vec2 pos = in_pos_angle.xy + in_vel * 100.0 * delta_time; vec2 vel = in_vel; if (pos.x > size.x) { pos.x = size.x; @@ -84,7 +85,7 @@ def __init__(self): pos.y = 0.0; vel.y *= -1.0; } - out_pos = vec3(pos, in_pos.z); + out_pos_angle = vec4(pos, in_pos_angle.zw); out_vel = vel; } """, @@ -103,19 +104,20 @@ def __init__(self): self.buffer_velocity_2 = self.ctx.buffer(reserve=self.buffer_velocity_1.size) # Create a buffer with the same size as the position buffer in the spritelist. # It's important that these match because we're copying that buffer into this one. - self.buffer_pos_copy = self.ctx.buffer(reserve=self.coins.buffer_positions.size) + self.buffer_pos_angle = cast(Buffer, self.coins.data.storage_positions_angle) + self.buffer_pos_angle_copy = self.ctx.buffer(reserve=self.buffer_pos_angle.size) # Geometry input: Copied positions and first velocity buffer self.geometry_1 = self.ctx.geometry( [ - BufferDescription(self.buffer_pos_copy, "3f", ["in_pos"]), + BufferDescription(self.buffer_pos_angle_copy, "4f", ["in_pos_angle"]), BufferDescription(self.buffer_velocity_1, "2f", ["in_vel"]), ] ) # Geometry input: Copied positions and second velocity buffer self.geometry_2 = self.ctx.geometry( [ - BufferDescription(self.buffer_pos_copy, "3f", ["in_pos"]), + BufferDescription(self.buffer_pos_angle_copy, "4f", ["in_pos_angle"]), BufferDescription(self.buffer_velocity_2, "2f", ["in_vel"]), ] ) @@ -124,13 +126,13 @@ def on_draw(self): self.clear() # Copy the position buffer. This happens on the gpu side. - self.buffer_pos_copy.copy_from_buffer(self.coins.buffer_positions) + self.buffer_pos_angle_copy.copy_from_buffer(self.buffer_pos_angle) # Run the transform writing new positions and velocities self.geometry_1.transform( self.program, [ - self.coins.buffer_positions, + self.buffer_pos_angle, self.buffer_velocity_2, ], ) diff --git a/arcade/examples/gl/spritelist_interaction_hijack_positions.py b/arcade/examples/gl/spritelist_interaction_hijack_positions.py index 19323a185c..d3da2cf72d 100644 --- a/arcade/examples/gl/spritelist_interaction_hijack_positions.py +++ b/arcade/examples/gl/spritelist_interaction_hijack_positions.py @@ -9,8 +9,12 @@ """ import math +from typing import cast + import arcade from arcade import hitbox +from arcade.sprite_list.sprite_list import SpriteListBufferData +from arcade.gl import Buffer NUM_COINS = 500 @@ -38,23 +42,24 @@ def __init__(self): // The current time to add some movement uniform float time; - // The "bendyness" value accelerating rotations + // The "bendiness" value accelerating rotations uniform float bend; // The current size of the screen uniform vec2 size; // The new positions we are writing into a new buffer - out vec3 out_pos; + out vec4 out_pos; void main() { // gl_VertexID is the sprite position in the spritelist. // We can use that to value to create unique positions with // some simple math. float vertId = float(gl_VertexID); - out_pos = vec3(size, 0.0) / 2.0 + vec3( + out_pos = vec4(size, 0.0, 0.0) / 2.0 + vec4( sin(vertId + time + vertId * bend), cos(vertId + time + vertId * bend), + 0.0, 0.0 ) * vertId; } @@ -65,11 +70,17 @@ def __init__(self): def on_draw(self): self.clear() + if not isinstance(self.coins.data, SpriteListBufferData): + raise RuntimeError( + "The spritelist data must be of type SpriteListBufferData." + ) + pos_angle_buffer = cast(Buffer, self.coins.data.storage_positions_angle) + # Write the new positions directly into the position # buffer of the spritelist. A little bit rude, but it works. - self.coins.geometry.transform( + self.coins.data.geometry.transform( self.position_program, - self.coins.buffer_positions, + pos_angle_buffer, vertices=len(self.coins), ) self.coins.draw() @@ -77,7 +88,7 @@ def on_draw(self): def on_update(self, delta_time: float): # Keep updating the current time to animation the movement self.position_program["time"] = self.time / 4 - # Update the "bendyness" value + # Update the "bendiness" value self.position_program["bend"] = math.cos(self.time) / 400 def on_resize(self, width: int, height: int): diff --git a/arcade/examples/gl/spritelist_interaction_visualize_dist.py b/arcade/examples/gl/spritelist_interaction_visualize_dist.py index 1bab87056a..b87926b7d0 100644 --- a/arcade/examples/gl/spritelist_interaction_visualize_dist.py +++ b/arcade/examples/gl/spritelist_interaction_visualize_dist.py @@ -49,14 +49,14 @@ def __init__(self): #version 330 // Sprite positions from SpriteList - in vec3 in_pos; + in vec4 in_pos; // Output to geometry shader out vec3 v_position; void main() { // This shader just forwards info to geo shader - v_position = in_pos; + v_position = in_pos.xyz; } """, geometry_shader=""" @@ -120,7 +120,7 @@ def on_draw(self): # use to run our shader/gpu program. It only requires that we # use correctly named input name(s). in_pos in this example # what will automatically map in the position buffer to the vertex shader. - self.coins.geometry.render(self.program_visualize_dist, vertices=len(self.coins)) + self.coins.data.geometry.render(self.program_visualize_dist, vertices=len(self.coins)) arcade.draw_sprite(self.player) # Visualize the interaction radius diff --git a/arcade/examples/gl/spritelist_interaction_visualize_dist_los.py b/arcade/examples/gl/spritelist_interaction_visualize_dist_los.py index 8e0e30f2e0..bc29895d66 100644 --- a/arcade/examples/gl/spritelist_interaction_visualize_dist_los.py +++ b/arcade/examples/gl/spritelist_interaction_visualize_dist_los.py @@ -72,14 +72,14 @@ def __init__(self): #version 330 // Sprite positions from SpriteList - in vec3 in_pos; + in vec4 in_pos; // Output to geometry shader out vec3 v_position; void main() { // This shader just forwards info to geo shader - v_position = in_pos; + v_position = in_pos.xyz; } """, geometry_shader=""" @@ -178,7 +178,7 @@ def on_draw(self): # use to run our shader/gpu program. It only requires that we # use correctly named input name(s). in_pos in this example # what will automatically map in the position buffer to the vertex shader. - self.coins.geometry.render(self.program_visualize_dist, vertices=len(self.coins)) + self.coins.data.geometry.render(self.program_visualize_dist, vertices=len(self.coins)) arcade.draw_sprite(self.player) # Visualize the interaction radius diff --git a/arcade/examples/gl/spritelist_interaction_visualize_dist_los_trans.py b/arcade/examples/gl/spritelist_interaction_visualize_dist_los_trans.py index 0dd505ef01..8467036bc3 100644 --- a/arcade/examples/gl/spritelist_interaction_visualize_dist_los_trans.py +++ b/arcade/examples/gl/spritelist_interaction_visualize_dist_los_trans.py @@ -80,14 +80,14 @@ def __init__(self): #version 330 // Sprite positions from SpriteList - in vec3 in_pos; + in vec4 in_pos; // Output to geometry shader out vec3 v_position; void main() { // This shader just forwards info to geo shader - v_position = in_pos; + v_position = in_pos.xyz; } """, geometry_shader=""" @@ -183,7 +183,7 @@ def on_draw(self): # use to run our shader/gpu program. It only requires that we # use correctly named input name(s). in_pos in this example # what will automatically map in the position buffer to the vertex shader. - self.coins.geometry.transform( + self.coins.data.geometry.transform( self.program_select_sprites, self.result_buffer, vertices=len(self.coins), diff --git a/arcade/sprite_list/sprite_list.py b/arcade/sprite_list/sprite_list.py index 83887a83b6..1eadcad1c8 100644 --- a/arcade/sprite_list/sprite_list.py +++ b/arcade/sprite_list/sprite_list.py @@ -323,11 +323,11 @@ def _init_deferred(self) -> None: # NOTE: Instantiate the appropriate spritelist data class here # Desktop GL (with geo shader) - # self._data = SpriteListBufferData( + self._data = SpriteListBufferData(self.ctx, capacity=self._buf_capacity, atlas=self._atlas) + # WebGL (without geo shader) + # self._data = SpriteListTextureData( # self.ctx, capacity=self._buf_capacity, atlas=self._atlas # ) - # WebGL (without geo shader) - self._data = SpriteListTextureData(self.ctx, capacity=self._buf_capacity, atlas=self._atlas) self._initialized = True # Load all the textures and write texture coordinates into buffers. @@ -1260,6 +1260,7 @@ def __init__(self, ctx: ArcadeContext, capacity: int) -> None: self.ctx = ctx self._buf_capacity = capacity self._idx_capacity = capacity + self._geometry: Geometry # Generic GPU storage for sprite data self._storage_pos_angle: Buffer | Texture2D @@ -1268,6 +1269,13 @@ def __init__(self, ctx: ArcadeContext, capacity: int) -> None: self._storage_texture_id: Buffer | Texture2D self._storage_index: Buffer | Texture2D + @property + def geometry(self) -> Geometry: + """ + Returns the internal OpenGL geometry for this spritelist. + """ + return self._geometry + @property def storage_positions_angle(self) -> Buffer | Texture2D: """ @@ -1441,23 +1449,6 @@ def __init__(self, ctx: ArcadeContext, capacity: int, atlas: TextureAtlasBase) - index_element_size=4, # 32 bit integers ) - @property - def geometry(self) -> Geometry: - """ - Returns the internal OpenGL geometry for this spritelist. - This can be used to execute custom shaders with the - spritelist data. - - One or multiple of the following inputs must be defined in your vertex shader:: - - in vec2 in_pos; - in float in_angle; - in vec2 in_size; - in float in_texture; - in vec4 in_color; - """ - return self._geometry - @property def buffer_positions_angle(self) -> Buffer: """