Skip to content

Commit 69d18ec

Browse files
WIP
1 parent ad39c44 commit 69d18ec

File tree

6 files changed

+384
-61
lines changed

6 files changed

+384
-61
lines changed

Diff for: src/patterned.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
pmma.set_clean_profiling(False)
77
pmma.set_profile_result_path(r"H:\Downloads\60 profile.txt")
8-
pmma.init(general_profile_application=True)
9-
#pmma.init(general_profile_application=False, use_c_acceleration=True)
8+
#pmma.init(general_profile_application=True)
9+
pmma.init(general_profile_application=False, use_c_acceleration=True) ## peak 53, stabilizes at 50
1010

1111
display = pmma.Display()
1212
display.create(vsync=False)

Diff for: src/rings.py

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import pygame
2+
import moderngl
3+
import numpy as np
4+
from pyrr import Matrix44, Vector3
5+
import pmma
6+
import time
7+
8+
pmma.init()
9+
10+
class Ring:
11+
def __init__(self, ctx, index, inner_radius=0.3, outer_radius=0.5, segments=64, rings=32):
12+
"""Creates a 3D ring with smooth shading."""
13+
self.ctx = ctx
14+
self.outer_radius = outer_radius
15+
self.program = self.create_shader()
16+
17+
# Generate torus vertices, normals, and indices
18+
self.vbo, self.ibo, self.num_indices = self.generate_torus(inner_radius, outer_radius, segments, rings)
19+
20+
# Create a VAO (Vertex Array Object)
21+
self.vao = self.ctx.vertex_array(
22+
self.program, [(self.vbo, '3f 3f', 'in_position', 'in_normal')], self.ibo
23+
)
24+
self.color = pmma.ColorConverter()
25+
self.start = time.perf_counter()
26+
self.index = (index * 50) / 300
27+
28+
def create_shader(self):
29+
"""Creates the shader program for smooth shading."""
30+
return self.ctx.program(
31+
vertex_shader="""
32+
#version 330
33+
uniform mat4 model;
34+
uniform mat4 view;
35+
uniform mat4 projection;
36+
uniform float scale;
37+
in vec3 in_position;
38+
in vec3 in_normal;
39+
out vec3 frag_normal;
40+
void main() {
41+
frag_normal = normalize(mat3(model) * in_normal);
42+
gl_Position = projection * view * model * vec4(in_position * scale, 1.0);
43+
}
44+
""",
45+
fragment_shader="""
46+
#version 330
47+
in vec3 frag_normal;
48+
out vec4 fragColor;
49+
uniform vec3 u_color;
50+
void main() {
51+
vec3 normal = gl_FrontFacing ? frag_normal : -frag_normal; // Flip normal for back-faces
52+
float light = dot(normalize(normal), vec3(0.0, 0.0, 1.0)) * 0.5 + 0.5;
53+
fragColor = vec4(u_color.rgb, 1.0) * light;
54+
}
55+
"""
56+
)
57+
58+
def generate_torus(self, inner_radius, outer_radius, segments, rings):
59+
"""Generates torus (ring) vertices, normals, and indices."""
60+
vertices = []
61+
indices = []
62+
63+
for i in range(rings):
64+
theta = i * 2 * np.pi / rings
65+
cos_theta, sin_theta = np.cos(theta), np.sin(theta)
66+
67+
for j in range(segments):
68+
phi = j * 2 * np.pi / segments
69+
cos_phi, sin_phi = np.cos(phi), np.sin(phi)
70+
71+
# Vertex position
72+
x = (outer_radius + inner_radius * cos_phi) * cos_theta
73+
y = (outer_radius + inner_radius * cos_phi) * sin_theta
74+
z = inner_radius * sin_phi
75+
76+
# Normal vector
77+
nx = cos_phi * cos_theta
78+
ny = cos_phi * sin_theta
79+
nz = sin_phi
80+
81+
vertices.extend([x, y, z, nx, ny, nz])
82+
83+
for i in range(rings):
84+
for j in range(segments):
85+
next_i = (i + 1) % rings
86+
next_j = (j + 1) % segments
87+
88+
indices.extend([
89+
i * segments + j, next_i * segments + j, i * segments + next_j,
90+
next_i * segments + j, next_i * segments + next_j, i * segments + next_j
91+
])
92+
93+
vbo = self.ctx.buffer(np.array(vertices, dtype='f4'))
94+
ibo = self.ctx.buffer(np.array(indices, dtype='i4'))
95+
96+
return vbo, ibo, len(indices)
97+
98+
def render(self, projection_matrix, view_matrix, rotation):
99+
"""Renders the ring with smooth shading."""
100+
self.program['model'].write(rotation.astype('f4'))
101+
self.program['view'].write(view_matrix.astype('f4'))
102+
self.program['projection'].write(projection_matrix.astype('f4'))
103+
self.program['u_color'].write(self.color.generate_color_from_perlin_noise(time.perf_counter() - self.start, format=pmma.Constants.SMALL_RGB))
104+
self.program['scale'] = self.index
105+
self.vao.render(moderngl.TRIANGLES)
106+
107+
108+
class Renderer:
109+
def __init__(self, width=1920, height=1080):
110+
pygame.init()
111+
pygame.display.set_mode((width, height), pygame.OPENGL | pygame.DOUBLEBUF)
112+
self.ctx = moderngl.create_context()
113+
self.clock = pygame.time.Clock()
114+
self.width, self.height = width, height
115+
116+
# Create multiple smooth ring instances
117+
# Generate 100 concentric rings
118+
self.rings = [
119+
Ring(self.ctx, i, inner_radius=1, outer_radius=2) for i in range(10)
120+
]
121+
122+
123+
# Determine largest ring radius
124+
self.max_radius = max(ring.outer_radius for ring in self.rings)
125+
126+
# Camera setup
127+
self.setup_camera()
128+
129+
self.ctx.enable(moderngl.CULL_FACE) # Hide inside faces
130+
self.ctx.front_face = 'ccw' # Ensure correct front-face
131+
self.ctx.enable(moderngl.DEPTH_TEST) # Fix depth sorting issues
132+
133+
def setup_camera(self):
134+
"""Set up the projection and view matrices to focus on the rings."""
135+
fov = 45 # Field of View
136+
aspect_ratio = self.width / self.height
137+
near_plane = 0.001
138+
far_plane = 1000.0
139+
140+
# Projection matrix (Perspective)
141+
self.projection = Matrix44.perspective_projection(fov, aspect_ratio, near_plane, far_plane)
142+
143+
# Camera position: Distance should be enough to see the largest ring
144+
camera_distance = 15#self.rings[-1].outer_radius * 2.5
145+
self.camera_position = Vector3([0.0, 0.0, camera_distance])
146+
147+
# View matrix: Looking at the center from `camera_position`
148+
self.view = Matrix44.look_at(
149+
eye=self.camera_position, # Camera position
150+
target=Vector3([0.0, 0.0, 0.0]), # Looking at the origin
151+
up=Vector3([0.0, 1.0, 0.0]) # Up direction
152+
)
153+
154+
def run(self):
155+
"""Main render loop."""
156+
angle = 0
157+
running = True
158+
while running:
159+
for event in pygame.event.get():
160+
if event.type == pygame.QUIT:
161+
running = False
162+
163+
self.ctx.clear(0.1, 0.1, 0.1)
164+
165+
# Rotate rings
166+
angle += 1
167+
index = 0
168+
for ring in self.rings:
169+
rotation = Matrix44.from_eulers((index + (angle * np.pi / 180), index + (angle * np.pi / 180), index + (angle * np.pi / 180)))
170+
ring.render(self.projection, self.view, rotation)
171+
index += 0# 0.1
172+
173+
pygame.display.flip()
174+
self.clock.tick(60)
175+
176+
pygame.quit()
177+
178+
179+
if __name__ == "__main__":
180+
Renderer().run()

Diff for: src/shaders/ring_fragment.glsl

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#version 330
2+
3+
in vec3 frag_normal;
4+
out vec4 fragColor;
5+
uniform vec3 u_color;
6+
7+
void main() {
8+
float light = dot(normalize(frag_normal), vec3(0.0, 0.0, 1.0)) * 0.5 + 0.5;
9+
fragColor = vec4(u_color * light, 1.0);
10+
}

Diff for: src/shaders/ring_vertex.glsl

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#version 330
2+
3+
in vec3 in_position;
4+
in vec3 in_normal;
5+
uniform mat4 model;
6+
uniform mat4 projection;
7+
8+
out vec3 frag_normal;
9+
10+
void main() {
11+
gl_Position = projection * model * vec4(in_position, 1.0);
12+
frag_normal = normalize(mat3(model) * in_normal);
13+
}

Diff for: src/squares.py

+20-59
Original file line numberDiff line numberDiff line change
@@ -5,94 +5,55 @@
55
import pygame
66
import math
77

8+
pmma.init()
9+
810
canvas = pmma.Display()
9-
canvas.create(1280, 720)
11+
canvas.create(1920, 1080, full_screen=True)
1012
events = pmma.Events()
1113

12-
registry = pmma.Registry
13-
1414
color_perlin = pmma.Perlin(random.randint(0, 9999))
1515
rotation_perlin = pmma.Perlin(random.randint(0, 9999))
1616

17-
SWITCH = False
18-
19-
def draw_rectangle(x, y, width, height, color, rotation=0): # https://stackoverflow.com/a/73855696
20-
"""Draw a rectangle, centered at x, y.
21-
All credit to Tim Swast for this `function that helped make this possible!
22-
23-
Arguments:
24-
x (int/float):
25-
The x coordinate of the center of the shape.
26-
y (int/float):
27-
The y coordinate of the center of the shape.
28-
width (int/float):
29-
The width of the rectangle.
30-
height (int/float):
31-
The height of the rectangle.
32-
color (str):
33-
Name of the fill color, in HTML format.
34-
"""
35-
points = []
36-
37-
# The distance from the center of the rectangle to
38-
# one of the corners is the same for each corner.
39-
radius = math.sqrt((height / 2)**2 + (width / 2)**2)
40-
41-
# Get the angle to one of the corners with respect
42-
# to the x-axis.
43-
angle = math.atan2(height / 2, width / 2)
44-
45-
# Transform that angle to reach each corner of the rectangle.
46-
angles = [angle, -angle + math.pi, angle + math.pi, -angle]
47-
48-
# Convert rotation from degrees to radians.
49-
rot_radians = (math.pi / 180) * rotation
50-
51-
# Calculate the coordinates of each point.
52-
for angle in angles:
53-
y_offset = -1 * radius * math.sin(angle + rot_radians)
54-
x_offset = radius * math.cos(angle + rot_radians)
55-
points.append((x + x_offset, y + y_offset))
56-
57-
pygame.draw.polygon(canvas.surface, color, points)
58-
5917
class Square:
6018
def __init__(self, n):
6119
self.n = n/10
6220
self.size = n
6321
self.iter = n
6422

23+
self.rectangle = pmma.Rectangle()
24+
self.rectangle.set_center((0, 0), pmma.Constants.OPENGL_COORDINATES)
25+
self.rectangle.set_size((self.size, self.size))
26+
self.color = pmma.ColorConverter(seed=0)
27+
6528
def render(self, now_time):
66-
color = [
67-
color_perlin.generate_2D_perlin_noise((now_time+self.n)/75, 0, [0, 255]),
68-
color_perlin.generate_2D_perlin_noise(0, (now_time+self.n)/75, [0, 255]),
69-
color_perlin.generate_2D_perlin_noise(-(now_time+self.n)/75, 0, [0, 255])
70-
]
71-
draw_rectangle(*center, self.size, self.size, color, rotation=self.n)
72-
73-
if SWITCH:
74-
self.n = rotation_perlin.generate_2D_perlin_noise(-(now_time+self.iter)/1000, 0, [0, 360]) # 500
75-
else:
76-
self.n += 0.5
29+
self.rectangle.set_rotation(self.n)
30+
self.rectangle.set_color(self.color.generate_color_from_perlin_noise((now_time+self.n)/75, format=pmma.Constants.RGB))
31+
32+
self.rectangle.render()
33+
34+
self.n += 0.01
7735

7836
squares = []
7937
diag = int(math.sqrt(canvas.get_width()**2 + canvas.get_width()**2))
8038
for i in range(0, diag, 8):
8139
squares.append(Square(diag-i))
8240

41+
print(i)
42+
8343
start = time.perf_counter()
8444
now_time = 0
85-
while registry.running:
45+
while True:
8646
#k = time.perf_counter()
8747
center = (canvas.get_width()/2, canvas.get_height()/2)
8848

89-
canvas.clear(pygame.transform.average_color(canvas.surface))
49+
canvas.clear()
9050

9151
events.handle(canvas)
9252

9353
for square in squares:
9454
square.render(now_time)
9555

96-
canvas.refresh(refresh_rate=15)
56+
pmma.compute()
57+
canvas.refresh()
9758
now_time = time.perf_counter() - start
9859
#s = time.perf_counter()

0 commit comments

Comments
 (0)