@@ -118,3 +118,261 @@ kernel void convert_rgb565_to_bgra8888(texture2d<ushort, access::read> in [[ te
118118
119119 out.write (half4 (pix2) / half4 (0x1f , 0x3f , 0x1f , 0xf ), gid);
120120}
121+
122+ #pragma mark - ribbon simple
123+
124+ namespace ribbon {
125+
126+ float iqhash (float n)
127+ {
128+ return fract (sin (n) * 43758.5453 );
129+ }
130+
131+ float noise (float3 x)
132+ {
133+ float3 p = floor (x);
134+ float3 f = fract (x);
135+ f = f * f * (3.0 - 2.0 * f);
136+ float n = p.x + p.y * 57.0 + 113.0 * p.z ;
137+ return mix (mix (mix (iqhash (n), iqhash (n + 1.0 ), f.x ),
138+ mix (iqhash (n + 57.0 ), iqhash (n + 58.0 ), f.x ), f.y ),
139+ mix (mix (iqhash (n + 113.0 ), iqhash (n + 114.0 ), f.x ),
140+ mix (iqhash (n + 170.0 ), iqhash (n + 171.0 ), f.x ), f.y ), f.z );
141+ }
142+
143+ float xmb_noise2 (float3 x, const device Uniforms &constants)
144+ {
145+ return cos (x.z * 4.0 ) * cos (x.z + constants.time / 10.0 + x.x );
146+ }
147+
148+ }
149+
150+ #pragma mark - ribbon simple
151+
152+ vertex FontFragmentIn ribbon_simple_vertex (const SpriteVertex in [[ stage_in ]], const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
153+ {
154+ float4 t = (constants.projectionMatrix * float4 (in.position , 0 , 1 ));
155+
156+ float3 v = float3 (t.x , 0.0 , 1.0 -t.y );
157+ float3 v2 = v;
158+
159+ v2.x = v2.x + constants.time / 2.0 ;
160+ v2.z = v.z * 3.0 ;
161+ v.y = cos ((v.x + v.z / 3.0 + constants.time ) * 2.0 ) / 10.0 + ribbon::noise (v2.xyz ) / 4.0 ;
162+ v.y = -v.y ;
163+
164+ FontFragmentIn out;
165+ out.position = float4 (v, 1.0 );
166+ return out;
167+ }
168+
169+ fragment float4 ribbon_simple_fragment ()
170+ {
171+ return float4 (0.05 , 0.05 , 0.05 , 1.0 );
172+ }
173+
174+ #pragma mark - ribbon
175+
176+ typedef struct
177+ {
178+ vector_float4 position [[position]];
179+ vector_float3 vEC;
180+ } RibbonOutIn;
181+
182+ vertex RibbonOutIn ribbon_vertex (const SpriteVertex in [[ stage_in ]], const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
183+ {
184+ float4 t = (constants.projectionMatrix * float4 (in.position , 0 , 1 ));
185+
186+ float3 v = float3 (t.x , 0.0 , 1.0 -t.y );
187+ float3 v2 = v;
188+ float3 v3 = v;
189+
190+ v.y = ribbon::xmb_noise2 (v2, constants) / 8.0 ;
191+
192+ v3.x -= constants.time / 5.0 ;
193+ v3.x /= 4.0 ;
194+
195+ v3.z -= constants.time / 10.0 ;
196+ v3.y -= constants.time / 100.0 ;
197+
198+ v.z -= ribbon::noise (v3 * 7.0 ) / 15.0 ;
199+ v.y -= ribbon::noise (v3 * 7.0 ) / 15.0 + cos (v.x * 2.0 - constants.time / 2.0 ) / 5.0 - 0.3 ;
200+ v.y = -v.y ;
201+
202+ RibbonOutIn out;
203+ out.vEC = v;
204+ out.position = float4 (v, 1.0 );
205+ return out;
206+ }
207+
208+ fragment float4 ribbon_fragment (RibbonOutIn in [[ stage_in ]])
209+ {
210+ const float3 up = float3 (0.0 , 0.0 , 1.0 );
211+ float3 x = dfdx (in.vEC );
212+ float3 y = dfdy (in.vEC );
213+ y = -y; /* Flip Y derivative to match Vulkan's yflip */
214+ float3 normal = normalize (cross (x, y));
215+ float c = 1.0 - dot (normal, up);
216+ c = (1.0 - cos (c * c)) / 3.0 ;
217+ return float4 (c, c, c, 1.0 );
218+ }
219+
220+ #pragma mark - snow constants
221+
222+ constant float snowBaseScale [[ function_constant(0 ) ]]; // [1.0 .. 10.0]
223+ constant float snowDensity [[ function_constant(1 ) ]]; // [0.01 .. 1.0]
224+ constant float snowSpeed [[ function_constant(2 ) ]]; // [0.1 .. 1.0]
225+
226+ #pragma mark - snow simple
227+
228+ namespace snow
229+ {
230+
231+ float rand (float2 co)
232+ {
233+ return fract (sin (dot (co.xy , float2 (12.9898 , 78.233 ))) * 43758.5453 );
234+ }
235+
236+ float dist_func (float2 distv)
237+ {
238+ float dist = sqrt ((distv.x * distv.x ) + (distv.y * distv.y )) * (40.0 / snowBaseScale);
239+ dist = clamp (dist, 0.0 , 1.0 );
240+ return cos (dist * (3.14159265358 * 0.5 )) * 0.5 ;
241+ }
242+
243+ float random_dots (float2 co)
244+ {
245+ float part = 1.0 / 20.0 ;
246+ float2 cd = floor (co / part);
247+ float p = rand (cd);
248+
249+ if (p > 0.005 * (snowDensity * 40.0 ))
250+ return 0.0 ;
251+
252+ float2 dpos = (float2 (fract (p * 2.0 ) , p) + float2 (2.0 , 2.0 )) * 0.25 ;
253+
254+ float2 cellpos = fract (co / part);
255+ float2 distv = (cellpos - dpos);
256+
257+ return dist_func (distv);
258+ }
259+
260+ float snow (float2 pos, float time, float scale)
261+ {
262+ // add wobble
263+ pos.x += cos (pos.y * 1.2 + time * 3.14159 * 2.0 + 1.0 / scale) / (8.0 / scale) * 4.0 ;
264+ // add gravity
265+ pos += time * scale * float2 (-0.5 , 1.0 ) * 4.0 ;
266+ return random_dots (pos / scale) * (scale * 0.5 + 0.5 );
267+ }
268+
269+ }
270+
271+ fragment float4 snow_fragment (FontFragmentIn in [[ stage_in ]],
272+ const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
273+ {
274+ float tim = constants.time * 0.4 * snowSpeed;
275+ float2 pos = in.position .xy / constants.outputSize .xx ;
276+ pos.y = 1.0 - pos.y ; // Flip Y
277+ float a = 0.0 ;
278+ // Each of these is a layer of snow
279+ // Remove some for better performance
280+ // Changing the scale (3rd value) will mess with the looping
281+ a += snow::snow (pos, tim, 1.0 );
282+ a += snow::snow (pos, tim, 0.7 );
283+ a += snow::snow (pos, tim, 0.6 );
284+ a += snow::snow (pos, tim, 0.5 );
285+ a += snow::snow (pos, tim, 0.4 );
286+ a += snow::snow (pos, tim, 0.3 );
287+ a += snow::snow (pos, tim, 0.25 );
288+ a += snow::snow (pos, tim, 0.125 );
289+ a = a * min (pos.y * 4.0 , 1.0 );
290+ return float4 (1.0 , 1.0 , 1.0 , a);
291+ }
292+
293+ fragment float4 bokeh_fragment (FontFragmentIn in [[ stage_in ]],
294+ const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
295+ {
296+ float speed = constants.time * 4.0 ;
297+ float2 uv = -1.0 + 2.0 * in.position .xy / constants.outputSize ;
298+ uv.y = -uv.y ; /* Flip Y to match Vulkan's yflip */
299+ uv.x *= constants.outputSize .x / constants.outputSize .y ;
300+ float3 color = float3 (0.0 );
301+
302+ for ( int i=0 ; i < 8 ; i++ )
303+ {
304+ float pha = sin (float (i) * 546.13 + 1.0 ) * 0.5 + 0.5 ;
305+ float siz = pow (sin (float (i) * 651.74 + 5.0 ) * 0.5 + 0.5 , 4.0 );
306+ float pox = sin (float (i) * 321.55 + 4.1 ) * constants.outputSize .x / constants.outputSize .y ;
307+ float rad = 0.1 + 0.5 * siz + sin (pha + siz) / 4.0 ;
308+ float2 pos = float2 (pox + sin (speed / 15 . + pha + siz), - 1.0 - rad + (2.0 + 2.0 * rad) * fract (pha + 0.3 * (speed / 7 .) * (0.2 + 0.8 * siz)));
309+ float dis = length (uv - pos);
310+ if (dis < rad)
311+ {
312+ float3 col = mix (float3 (0.194 * sin (speed / 6.0 ) + 0.3 , 0.2 , 0.3 * pha), float3 (1.1 * sin (speed / 9.0 ) + 0.3 , 0.2 * pha, 0.4 ), 0.5 + 0.5 * sin (float (i)));
313+ color += col.zyx * (1.0 - smoothstep (rad * 0.15 , rad, dis));
314+ }
315+ }
316+ color *= sqrt (1.5 - 0.5 * length (uv));
317+ return float4 (color.r , color.g , color.b , 0.5 );
318+ }
319+
320+ namespace snowflake {
321+
322+ float rand_float (float x)
323+ {
324+ return snow::rand (float2 (x, 1.0 ));
325+ }
326+
327+ float snow (float3 pos, float2 uv, float o, float atime)
328+ {
329+ float2 d = (pos.xy - uv);
330+ float a = atan (d.y / d.x ) + sin (atime*1.0 + o) * 10.0 ;
331+
332+ float dist = d.x *d.x + d.y *d.y ;
333+
334+ if (dist < pos.z /400.0 )
335+ {
336+ float col = 0.0 ;
337+ if (sin (a * 8.0 ) < 0.0 )
338+ col = 1.0 ;
339+ if (dist < pos.z /800.0 )
340+ col += 1.0 ;
341+ return col * pos.z ;
342+ }
343+
344+ return 0.0 ;
345+ }
346+
347+ float col (float2 c, const device Uniforms &constants)
348+ {
349+ float color = 0.0 ;
350+ float atime = (constants.time + 1.0 ) / 4.0 ;
351+
352+ for (int i = 1 ; i < 15 ; i++)
353+ {
354+ float o = rand_float (float (i) / 3.0 ) * 15.0 ;
355+ float z = rand_float (float (i) + 13.0 );
356+ float x = 1.8 - (3.6 ) * (rand_float (floor ((constants.time *((z + 1.0 ) / 2.0 ) +o) / 2.0 )) + sin (constants.time * o /1000.0 ) / 10.0 );
357+ float y = 1.0 - fmod ((constants.time * ((z + 1.0 )/2.0 )) + o, 2.0 );
358+
359+ color += snow (float3 (x,y,z), c, o, atime);
360+ }
361+
362+ return color;
363+ }
364+
365+ }
366+
367+ fragment float4 snowflake_fragment (FontFragmentIn in [[ stage_in ]],
368+ const device Uniforms &constants [[ buffer(BufferIndexUniforms) ]])
369+ {
370+ float2 uv = in.position .xy / constants.outputSize .xy ;
371+ uv = uv * 2.0 - 1.0 ;
372+ float2 p = uv;
373+ p.x *= constants.outputSize .x / constants.outputSize .y ;
374+ p.y = -p.y ; /* Flip Y so snowflakes fall down */
375+
376+ float c = snowflake::col (p, constants);
377+ return float4 (c,c,c,c);
378+ }
0 commit comments