commit 26c91ea093811c35822367b5478009c6e48a7cd6 Author: Looki2000 Date: Sat May 13 22:35:56 2023 +0200 first commit diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..12d63e7 Binary files /dev/null and b/logo.png differ diff --git a/logo_new.png b/logo_new.png new file mode 100644 index 0000000..5725ec8 Binary files /dev/null and b/logo_new.png differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..a4ec2a5 --- /dev/null +++ b/main.py @@ -0,0 +1,288 @@ +import pygame +import pygame.gfxdraw +from PIL import Image +import random +from math import cos, sin + +##### CONFIG ##### +window_size = (1280, 720) + +fps = 60 + +# pixel size in percentage of window height (0.0 - 1.0) +pixel_size = 0.018 + +# min and max distance from screen edge to pixel in window height percentage (0.0 - 1.0) +min_distribution_edge_dist = 0.1 +max_distribution_edge_dist = 0.2 + +initial_vel_randomness = 1 + +# max random delay of pixel simulation start in seconds +max_random_delay = 2 + + +## simulation settings +# 0.0 - inf +stiffness = 40 + +# 0.0 - 1.0 +damping = 0.08 + +################## + +damping_multiplier = 1 - damping + +target_delta_time = 1 / fps + +half_window_size = (window_size[0] / 2, window_size[1] / 2) + +print("=====================") + +aspect_ratio = window_size[0] / window_size[1] +half_aspect_ratio = aspect_ratio / 2 +print(f"Aspect ratio: {aspect_ratio}") + +pixel_size_px = pixel_size * window_size[1] +half_pixel_size_px = round(pixel_size_px / 2) +print(f"Pixel size: {pixel_size_px}px") + + +# import logo image +logo = Image.open("logo_new.png").convert("1") + + +logo_size = (logo.size[0] * pixel_size, logo.size[1] * pixel_size) +print(f"Logo size: {logo_size}") + +# offset in world space so the logo is in the center +#logo_offset = ((aspect_ratio - logo_size[0]) / 2, (1 - logo_size[1]) / 2) +logo_offset = (logo_size[0] / 2, logo_size[1] / 2) +print(f"Logo offset: {logo_offset}") + + +print("=====================") + + + + +pixels_target_pos = [] + +for y in range(logo.size[1]): + for x in range(logo.size[0]): + if logo.getpixel((x, y)) == 255: + pixels_target_pos.append((x * pixel_size - logo_offset[0], y * pixel_size - logo_offset[1])) + +pixels_target_pos = tuple(pixels_target_pos) + + +## distribute pixels in random positions off the screen + +pixels_pos_and_vel = [] + +for pixel in pixels_target_pos: + # select random screen edge axis using 1 and aspect_ratio as weights | 0 = x, 1 = y + edge_axis = random.choices((0, 1), weights=[1, aspect_ratio])[0] + + # select random edge | (x axis): 0 = left, 1 = right | (y axis): 0 = top, 1 = bottom + edge = random.choice((-1, 1)) + + # random position on edge + if edge_axis == 0: # x axis (vertical edges) + pos = [half_aspect_ratio * edge, random.uniform(-.5, .5)] + else: # y axis (horizontal edges) + pos = [random.uniform(-half_aspect_ratio, half_aspect_ratio), edge / 2] + + # offset pos by random 0 to distribution_edge_dist_px + pos[edge_axis] += random.uniform(min_distribution_edge_dist, max_distribution_edge_dist) * edge + + + # pos, velocity, delay + pixels_pos_and_vel.append([ + pos, + [random.uniform(-initial_vel_randomness, initial_vel_randomness), random.uniform(-initial_vel_randomness, initial_vel_randomness)], + random.uniform(0, max_random_delay) + 1 + ]) + + + + + + +# pygame init +pygame.init() +window = pygame.display.set_mode(window_size) +clock = pygame.time.Clock() + + + + + +rot_zoom_delay = 6 +rot_speed_increase = 0.2 +zoom_speed_increase = 0.65 + +rot_speed = 0 +zoom_speed = 0.04 + +fade_delay = 1.5 +fade_speed = 255/1.5 + +angle = 0 +zoom = 1 +fade_val = 255 + +can_rot = False + + +# main loop +while True: + # events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + quit() + + + window.fill((0, 0, 0)) + + if fade_val > 0: + if rot_zoom_delay > 0: + rot_zoom_delay -= target_delta_time + else: # zooming more and rotating + rot_speed += rot_speed_increase * target_delta_time + zoom_speed += zoom_speed_increase * target_delta_time + + angle += rot_speed * target_delta_time + + # rotate and zoom + rot_cos = cos(angle) + rot_sin = sin(angle) + + if not can_rot: + can_rot = True + + # fade + if fade_delay > 0: + fade_delay -= target_delta_time + else: + fade_val -= fade_speed * target_delta_time + if fade_val < 0: + continue + + zoom *= 1 + zoom_speed * target_delta_time + + # calculate pixel points positions + scaled_pixel_size_px = pixel_size_px * zoom + half_scaled_pixel_size_px = round(scaled_pixel_size_px / 2) + scaled_pixel_size_px = round(scaled_pixel_size_px) + + pixel_points = ( + (0, 0), + (scaled_pixel_size_px, 0), + (scaled_pixel_size_px, scaled_pixel_size_px), + (0, scaled_pixel_size_px) + ) + + pixel_points = tuple( + ( + pixel_point[0] - half_scaled_pixel_size_px, + pixel_point[1] - half_scaled_pixel_size_px + ) + for pixel_point in pixel_points + ) + + # rotate pixel points + if can_rot: + pixel_points = tuple( + ( + pixel_point[0] * rot_cos - pixel_point[1] * rot_sin, + pixel_point[0] * rot_sin + pixel_point[1] * rot_cos + ) + for pixel_point in pixel_points + ) + + + # draw pixels + for pixel_idx, pixel in enumerate(pixels_pos_and_vel): + # check if delay is over + if pixel[2] > 0: + pixel[2] -= target_delta_time + continue + + ## simulation (take target_delta_time into account) + + # get pixel pos and vel + pos = pixel[0] + vel = pixel[1] + + # delta pos (target pos - current pos) + delta_pos = [pixels_target_pos[pixel_idx][0] - pos[0], pixels_target_pos[pixel_idx][1] - pos[1]] + + # update velocity + vel[0] += delta_pos[0] * stiffness * target_delta_time + vel[1] += delta_pos[1] * stiffness * target_delta_time + + # damping + vel[0] *= damping_multiplier + vel[1] *= damping_multiplier + + # update pos + pos[0] += vel[0] * target_delta_time + pos[1] += vel[1] * target_delta_time + + # update pixel pos and vel + pixels_pos_and_vel[pixel_idx][0:2] = [pos, vel] + + + ## draw pixel + + # rotate + if can_rot: + pixel_draw_pos = ( + pos[0] * rot_cos - pos[1] * rot_sin, + pos[0] * rot_sin + pos[1] * rot_cos + ) + else: + pixel_draw_pos = pos + + # zoom + perceived_zoom = zoom + pixel_draw_pos = (pixel_draw_pos[0] * perceived_zoom, pixel_draw_pos[1] * perceived_zoom) + + # convert to screen space + pixel_draw_pos = ( + pixel_draw_pos[0] * window_size[1] + half_window_size[0], + pixel_draw_pos[1] * window_size[1] + half_window_size[1] + ) + + + # DEBUG draw sphere + #pygame.draw.circle(window, (255, 255, 255), (round(pixel_draw_pos[0]), round(pixel_draw_pos[1])), 200, 5) + + # DEBUG draw dot + #pygame.draw.circle(window, (255, 0, 0), (round(pixel_draw_pos[0]), round(pixel_draw_pos[1])), 1) + + # draw pixel + points = tuple( + (round(pixel_draw_pos[0] + pixel_point[0]), + round(pixel_draw_pos[1] + pixel_point[1])) for pixel_point in pixel_points + ) + + pygame.gfxdraw.aapolygon( + window, + points, + (fade_val,)*3 + ) + + pygame.gfxdraw.filled_polygon( + window, + points, + (fade_val,)*3 + ) + + + + # update + pygame.display.update() + clock.tick(60) \ No newline at end of file