1+ import pygame
2+ import moderngl
3+ import ctypes
4+ import sys
5+
6+ vertex_shader_sprite = """
7+ #version 330
8+ in vec2 in_position;
9+ in vec2 in_uv;
10+ out vec2 v_uv;
11+ void main()
12+ {
13+ v_uv = in_uv;
14+ gl_Position = vec4(in_position, 0.0, 1.0);
15+ }
16+ """
17+
18+ fragment_shader_sprite = """
19+ #version 330
20+ out vec4 fragColor;
21+ uniform sampler2D u_texture;
22+ uniform float y;
23+ in vec2 v_uv;
24+
25+ #define PI 3.1415926535897932384626433832795;
26+
27+ float rand(vec2 c){
28+ return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453);
29+ }
30+
31+ float noise(vec2 p, float freq ){
32+ float unit = 1/freq;
33+ vec2 ij = floor(p/unit);
34+ vec2 xy = mod(p,unit)/unit;
35+ xy = 3.*xy*xy-2.*xy*xy*xy;
36+ //xy = 0.5*(1.-cos(PI*xy));
37+ float a = rand((ij+vec2(0.,0.)));
38+ float b = rand((ij+vec2(1.,0.)));
39+ float c = rand((ij+vec2(0.,1.)));
40+ float d = rand((ij+vec2(1.,1.)));
41+ float x1 = mix(a, b, xy.x);
42+ float x2 = mix(c, d, xy.x);
43+ return mix(x1, x2, xy.y);
44+ }
45+
46+ float pNoise(vec2 p, int res){
47+ float persistance = .5;
48+ float n = 0.;
49+ float normK = 0.;
50+ float f = 4.;
51+ float amp = 1.;
52+ int iCount = 0;
53+ for (int i = 0; i<50; i++){
54+ n+=amp*noise(p, f);
55+ f*=2.;
56+ normK+=amp;
57+ amp*=persistance;
58+ if (iCount == res) break;
59+ iCount++;
60+ }
61+ float nf = n/normK;
62+ return nf*nf*nf*nf;
63+ }
64+
65+ void main()
66+ {
67+ //fragColor = texture(u_texture, v_uv)*pNoise(vec2(v_uv.x, y+v_uv.y), 1);
68+ vec2 new_v_uv = v_uv*2;
69+ float transparency = pNoise(vec2(new_v_uv.x, new_v_uv.y+y), 1);
70+ if (transparency < 0.075) {
71+ discard;
72+ } else {
73+ float y = y/3;
74+ fragColor = vec4(0.05+pNoise(vec2(y-50, -y+50), 1), 0.05+pNoise(vec2(-y, y), 1), 0.05+pNoise(vec2(y+600, y-750), 1), 1)*(0.9+transparency);
75+ }
76+ }
77+ """
78+
79+ class ModernGLGroup (pygame .sprite .Group ):
80+
81+ gl_context = None
82+ gl_program = None
83+ gl_buffer = None
84+ gl_vao = None
85+ gl_textures = {}
86+ y = 0
87+
88+ def __init__ (self , sprites = None ):
89+ if sprites == None :
90+ super ().__init__ ()
91+ else :
92+ super ().__init__ (sprites )
93+
94+ def get_program ():
95+ if ModernGLGroup .gl_program == None :
96+ ModernGLGroup .gl_program = ModernGLGroup .gl_context .program (
97+ vertex_shader = vertex_shader_sprite ,
98+ fragment_shader = fragment_shader_sprite )
99+ return ModernGLGroup .gl_program
100+
101+ def get_buffer ():
102+ if ModernGLGroup .gl_buffer == None :
103+ ModernGLGroup .gl_buffer = ModernGLGroup .gl_context .buffer (None , reserve = 6 * 4 * 4 )
104+ return ModernGLGroup .gl_buffer
105+
106+ def get_vao ():
107+ if ModernGLGroup .gl_vao == None :
108+ ModernGLGroup .gl_vao = ModernGLGroup .gl_context .vertex_array (
109+ ModernGLGroup .get_program (), [(ModernGLGroup .get_buffer (), "2f4 2f4" , "in_position" , "in_uv" )])
110+ return ModernGLGroup .gl_vao
111+
112+ def get_texture (image ):
113+ if not image in ModernGLGroup .gl_textures :
114+ rgba_image = image .convert_alpha ()
115+ texture = ModernGLGroup .gl_context .texture (rgba_image .get_size (), 4 , rgba_image .get_buffer ())
116+ texture .swizzle = 'BGRA'
117+ ModernGLGroup .gl_textures [image ] = texture
118+ return ModernGLGroup .gl_textures [image ]
119+
120+ def convert_vertex (pt , surface ):
121+ return pt [0 ] / surface .get_width () * 2 - 1 , 1 - pt [1 ] / surface .get_height () * 2
122+
123+ def render (sprite , surface ):
124+ corners = [
125+ ModernGLGroup .convert_vertex (sprite .rect .bottomleft , surface ),
126+ ModernGLGroup .convert_vertex (sprite .rect .bottomright , surface ),
127+ ModernGLGroup .convert_vertex (sprite .rect .topright , surface ),
128+ ModernGLGroup .convert_vertex (sprite .rect .topleft , surface )]
129+
130+ vertices_quad_2d = (ctypes .c_float * (6 * 4 ))(
131+ * corners [0 ], 0.0 , 1.0 ,
132+ * corners [1 ], 1.0 , 1.0 ,
133+ * corners [2 ], 1.0 , 0.0 ,
134+ * corners [0 ], 0.0 , 1.0 ,
135+ * corners [2 ], 1.0 , 0.0 ,
136+ * corners [3 ], 0.0 , 0.0 )
137+
138+ ModernGLGroup .get_buffer ().write (vertices_quad_2d )
139+ ModernGLGroup .get_program ()["y" ] = ModernGLGroup .y
140+ ModernGLGroup .get_texture (sprite .image ).use (0 )
141+ ModernGLGroup .get_vao ().render ()
142+ ModernGLGroup .y += 0.001
143+
144+ def draw (self , surface ):
145+ for sprite in self :
146+ ModernGLGroup .render (sprite , surface )
147+
148+ class SpriteObject (pygame .sprite .Sprite ):
149+ def __init__ (self , size ):
150+ super ().__init__ ()
151+ self .image = pygame .Surface (size , pygame .SRCALPHA )
152+ self .rect = self .image .get_rect (center = (size [0 ]// 2 , size [1 ]// 2 ))
153+
154+ pygame .init ()
155+
156+ window = pygame .display .set_mode (
157+ (1280 , 720 ),
158+ pygame .DOUBLEBUF | pygame .OPENGL | pygame .HWACCEL ,
159+ vsync = True )
160+ pygame .display .set_caption ("Colorful Stacked Patterns - 2" )
161+
162+ clock = pygame .time .Clock ()
163+
164+ gl_context = moderngl .create_context ()
165+ gl_context .enable (moderngl .BLEND )
166+ ModernGLGroup .gl_context = gl_context
167+
168+ sprite_object = SpriteObject (window .get_size ())
169+ group = ModernGLGroup (sprite_object )
170+
171+ run = True
172+ fullscreen = False
173+ while 1 :
174+ event_list = pygame .event .get ()
175+ for event in event_list :
176+ if event .type == pygame .QUIT :
177+ pygame .quit ()
178+ sys .exit ()
179+
180+ elif event .type == pygame .KEYDOWN :
181+ if event .key == pygame .K_ESCAPE :
182+ pygame .quit ()
183+ sys .exit ()
184+ elif event .key == pygame .K_F11 :
185+ fullscreen = not fullscreen
186+ if fullscreen :
187+ window = pygame .display .set_mode (
188+ (0 , 0 ),
189+ pygame .DOUBLEBUF | pygame .OPENGL | pygame .FULLSCREEN | pygame .HWACCEL ,
190+ vsync = True )
191+ else :
192+ window = pygame .display .set_mode (
193+ (1280 , 720 ),
194+ pygame .DOUBLEBUF | pygame .OPENGL | pygame .HWACCEL ,
195+ vsync = True )
196+
197+ ModernGLGroup .gl_context .viewport = (
198+ 0 ,
199+ 0 ,
200+ * pygame .display .get_window_size ())
201+
202+ sprite_object = SpriteObject (window .get_size ())
203+ group = ModernGLGroup (sprite_object )
204+ gl_context .clear (0 , 0 , 0 )
205+
206+ group .draw (window )
207+ pygame .display .flip ()
208+ clock .tick (200 )
209+
210+ pygame .quit ()
211+ exit ()
0 commit comments