import math
from dataclasses import dataclass, field
import numpy as np
from pybevy.prelude import *
from pybevy.wgpu import Extent3d, TextureFormat
IMAGE_WIDTH = 256
IMAGE_HEIGHT = 256
@resource
class MyProcGenImage(Resource):
def __init__(self, handle: Handle):
self.handle = handle
@dataclass
class IntWrapper:
value: int = 0
@dataclass
class ColorWrapper:
value: Color = field(default_factory=lambda: Color.WHITE)
def setup(commands: Commands, images: ResMut[Assets[Image]]) -> None:
commands.spawn(Camera2d())
beige = Color.srgb(0.96, 0.96, 0.86) beige_srgba = beige.to_srgba()
beige_bytes = [
int(beige_srgba.red * 255),
int(beige_srgba.green * 255),
int(beige_srgba.blue * 255),
int(beige_srgba.alpha * 255)
]
image = Image.new_fill(
Extent3d(IMAGE_WIDTH, IMAGE_HEIGHT, 1),
beige_bytes,
format=TextureFormat.Rgba8UnormSrgb,
)
center = Vec2(IMAGE_WIDTH / 2.0, IMAGE_HEIGHT / 2.0)
max_radius = min(IMAGE_HEIGHT, IMAGE_WIDTH) / 2.0
for y in range(IMAGE_HEIGHT):
for x in range(IMAGE_WIDTH):
r = Vec2(float(x), float(y)).distance(center)
a = 1.0 - min(r / max_radius, 1.0)
with image.pixel_bytes_mut(UVec3(x, y, 0)) as pixel_bytes:
pixel_bytes[3] = int(a * 255)
handle = images.add(image)
commands.spawn(Sprite.from_image(handle))
commands.insert_resource(MyProcGenImage(handle))
def draw(
my_handle: Res[MyProcGenImage],
images: ResMut[Assets[Image]],
i: Local[IntWrapper],
draw_color: Local[ColorWrapper],
) -> None:
if i.value.value == 0:
draw_color.value.value = Color.linear_rgb(
float(np.random.random()),
float(np.random.random()),
float(np.random.random()),
)
image = images.get_mut(my_handle.handle)
if not image:
return
center = Vec2(IMAGE_WIDTH / 2.0, IMAGE_HEIGHT / 2.0)
max_radius = min(IMAGE_HEIGHT, IMAGE_WIDTH) / 2.0
rot_speed = 0.0123
period = 0.12345
r = math.sin(i.value.value * period) * max_radius
angle = i.value.value * rot_speed
xy = Vec2(math.cos(angle), math.sin(angle)) * r + center
x, y = int(xy.x), int(xy.y)
old_color = image.get_color_at(x, y)
if not old_color:
i.value.value += 1
return
if i.value.value % 1000 == 0:
draw_color.value.value = Color.linear_rgb(
float(np.random.random()),
float(np.random.random()),
float(np.random.random()),
)
new_color = draw_color.value.value.with_alpha(old_color.alpha())
image.set_color_at(x, y, new_color)
i.value.value += 1
@entrypoint
def main(app: App) -> App:
return (
app.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(FixedUpdate, draw)
)
if __name__ == "__main__":
main().run()