From 595d7fad43d038df3bb6a0ecd730c6e5a2286cbb Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 19 Nov 2023 00:43:44 +0100 Subject: [PATCH 1/7] Add iDate to glsl builtins --- wgpu/utils/shadertoy.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/wgpu/utils/shadertoy.py b/wgpu/utils/shadertoy.py index 997434ac..c09f987d 100644 --- a/wgpu/utils/shadertoy.py +++ b/wgpu/utils/shadertoy.py @@ -34,6 +34,7 @@ float i_time; float i_time_delta; int i_frame; +vec4 i_date; // Shadertoy compatibility, see we can use the same code copied from shadertoy website @@ -42,6 +43,7 @@ #define iTimeDelta i_time_delta #define iMouse i_mouse #define iFrame i_frame +#define iDate i_date #define mainImage shader_main """ @@ -56,6 +58,7 @@ float time; float time_delta; int frame; + vec4 date; }; layout(binding = 0) uniform ShadertoyInput input; @@ -67,7 +70,7 @@ i_time_delta = input.time_delta; i_mouse = input.mouse; i_frame = input.frame; - + i_date = input.date; vec2 uv = vec2(uv.x, 1.0 - uv.y); vec2 frag_coord = uv * i_resolution.xy; @@ -239,8 +242,9 @@ class Shadertoy: * ``i_frame``: the frame number * ``i_resolution``: the resolution of the shadertoy * ``i_mouse``: the mouse position in pixels + * ``i_date``: the current date and time as a vec4 (year, month, day, seconds) - For GLSL, you can also use the aliases ``iTime``, ``iTimeDelta``, ``iFrame``, ``iResolution``, and ``iMouse`` of these built-in variables, + For GLSL, you can also use the aliases ``iTime``, ``iTimeDelta``, ``iFrame``, ``iResolution``, ``iMouse`` and ``iDate`` of these built-in variables, the entry point function also has an alias ``mainImage``, so you can use the shader code copied from shadertoy website without making any changes. """ @@ -255,6 +259,7 @@ def __init__(self, shader_code, resolution=(800, 450), offscreen=False) -> None: ("time", "f", 1), ("time_delta", "f", 1), ("frame", "I", 1), + ("date", "f", 4), ) self._shader_code = shader_code @@ -428,10 +433,22 @@ def _update(self): if not hasattr(self, "_frame"): self._frame = 0 + + time_struct = time.localtime() + self._uniform_data["date"] = ( + float(time_struct.tm_year), + float(time_struct.tm_mon - 1), + float(time_struct.tm_mday), + time_struct.tm_hour * 3600 + + time_struct.tm_min * 60 + + time_struct.tm_sec + + now % 1, + ) self._uniform_data["frame"] = self._frame self._frame += 1 + def _draw_frame(self): # Update uniform buffer self._update() From 9bbd2854c02d700e7b5c25b0106c770207cfded5 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 20 Nov 2023 18:17:05 +0100 Subject: [PATCH 2/7] add iDate to wgsl builtins --- wgpu/utils/shadertoy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wgpu/utils/shadertoy.py b/wgpu/utils/shadertoy.py index c09f987d..19f70180 100644 --- a/wgpu/utils/shadertoy.py +++ b/wgpu/utils/shadertoy.py @@ -115,6 +115,7 @@ var i_time_delta: f32; var i_time: f32; var i_frame: u32; +var i_date: vec4; // TODO: more global variables // var i_frag_coord: vec2; @@ -130,6 +131,7 @@ time: f32, time_delta: f32, frame: u32, + date: vec4, }; struct Varyings { @@ -149,6 +151,7 @@ i_time_delta = input.time_delta; i_mouse = input.mouse; i_frame = input.frame; + i_date = input.date; let uv = vec2(in.uv.x, 1.0 - in.uv.y); @@ -444,7 +447,7 @@ def _update(self): + time_struct.tm_sec + now % 1, ) - + self._uniform_data["frame"] = self._frame self._frame += 1 From fed76206509a5bca15827084ce3a3d7aeecbf3b7 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 21 Nov 2023 01:33:46 +0100 Subject: [PATCH 3/7] Fix memory offset error --- wgpu/utils/shadertoy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wgpu/utils/shadertoy.py b/wgpu/utils/shadertoy.py index 19f70180..a98d9de7 100644 --- a/wgpu/utils/shadertoy.py +++ b/wgpu/utils/shadertoy.py @@ -262,6 +262,8 @@ def __init__(self, shader_code, resolution=(800, 450), offscreen=False) -> None: ("time", "f", 1), ("time_delta", "f", 1), ("frame", "I", 1), + ("_pad", "I", 1), # padding TODO: investigate + ("_pad2", "I", 1), # padding ("date", "f", 4), ) From e19a918492f64e1ae22b5e7011b72738bc377788 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 21 Nov 2023 17:41:18 +0100 Subject: [PATCH 4/7] Fix order of fields in Uniform array --- wgpu/utils/shadertoy.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/wgpu/utils/shadertoy.py b/wgpu/utils/shadertoy.py index a98d9de7..b41c9313 100644 --- a/wgpu/utils/shadertoy.py +++ b/wgpu/utils/shadertoy.py @@ -29,21 +29,21 @@ builtin_variables_glsl = """ #version 450 core -vec3 i_resolution; vec4 i_mouse; +vec4 i_date; +vec3 i_resolution; float i_time; float i_time_delta; int i_frame; -vec4 i_date; // Shadertoy compatibility, see we can use the same code copied from shadertoy website -#define iTime i_time +#define iMouse i_mouse +#define iDate i_date #define iResolution i_resolution +#define iTime i_time #define iTimeDelta i_time_delta -#define iMouse i_mouse #define iFrame i_frame -#define iDate i_date #define mainImage shader_main """ @@ -54,23 +54,23 @@ struct ShadertoyInput { vec4 mouse; + vec4 date; vec3 resolution; float time; float time_delta; int frame; - vec4 date; }; layout(binding = 0) uniform ShadertoyInput input; out vec4 FragColor; void main(){ - i_time = input.time; + i_mouse = input.mouse; + i_date = input.date; i_resolution = input.resolution; + i_time = input.time; i_time_delta = input.time_delta; - i_mouse = input.mouse; i_frame = input.frame; - i_date = input.date; vec2 uv = vec2(uv.x, 1.0 - uv.y); vec2 frag_coord = uv * i_resolution.xy; @@ -110,12 +110,12 @@ builtin_variables_wgsl = """ -var i_resolution: vec3; var i_mouse: vec4; +var i_date: vec4; +var i_resolution: vec3; var i_time_delta: f32; var i_time: f32; var i_frame: u32; -var i_date: vec4; // TODO: more global variables // var i_frag_coord: vec2; @@ -127,11 +127,11 @@ struct ShadertoyInput { mouse: vec4, + date: vec4, resolution: vec3, time: f32, time_delta: f32, frame: u32, - date: vec4, }; struct Varyings { @@ -146,12 +146,12 @@ @fragment fn main(in: Varyings) -> @location(0) vec4 { - i_time = input.time; + i_mouse = input.mouse; + i_date = input.date; i_resolution = input.resolution; + i_time = input.time; i_time_delta = input.time_delta; - i_mouse = input.mouse; i_frame = input.frame; - i_date = input.date; let uv = vec2(in.uv.x, 1.0 - in.uv.y); @@ -175,6 +175,8 @@ class UniformArray: """Convenience class to create a uniform array. Maybe we can make it a public util at some point. + Ensure that the order matches structs in the shader code. + See https://www.w3.org/TR/WGSL/#alignment-and-size for reference on alignment. """ def __init__(self, *args): @@ -258,13 +260,11 @@ class Shadertoy: def __init__(self, shader_code, resolution=(800, 450), offscreen=False) -> None: self._uniform_data = UniformArray( ("mouse", "f", 4), + ("date", "f", 4), ("resolution", "f", 3), ("time", "f", 1), ("time_delta", "f", 1), ("frame", "I", 1), - ("_pad", "I", 1), # padding TODO: investigate - ("_pad2", "I", 1), # padding - ("date", "f", 4), ) self._shader_code = shader_code From d54473c8a4d539dfe4e561bf7db1363e470b5447 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 21 Nov 2023 17:45:25 +0100 Subject: [PATCH 5/7] Fix style --- wgpu/utils/shadertoy.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wgpu/utils/shadertoy.py b/wgpu/utils/shadertoy.py index b41c9313..dc25063d 100644 --- a/wgpu/utils/shadertoy.py +++ b/wgpu/utils/shadertoy.py @@ -438,7 +438,7 @@ def _update(self): if not hasattr(self, "_frame"): self._frame = 0 - + time_struct = time.localtime() self._uniform_data["date"] = ( float(time_struct.tm_year), @@ -449,11 +449,10 @@ def _update(self): + time_struct.tm_sec + now % 1, ) - + self._uniform_data["frame"] = self._frame self._frame += 1 - def _draw_frame(self): # Update uniform buffer self._update() From 5a92ff530f09d933c07588fd58bf3f58d6d04411 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 21 Nov 2023 17:53:10 +0100 Subject: [PATCH 6/7] Add example for iDate --- examples/shadertoy_glsl_clock.py | 94 ++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 examples/shadertoy_glsl_clock.py diff --git a/examples/shadertoy_glsl_clock.py b/examples/shadertoy_glsl_clock.py new file mode 100644 index 00000000..09597ad2 --- /dev/null +++ b/examples/shadertoy_glsl_clock.py @@ -0,0 +1,94 @@ +from wgpu.utils.shadertoy import Shadertoy + +shader_code = """ +// source: https://www.shadertoy.com/view/MdVcRd + +// See https://www.shadertoy.com/view/ldKGRR + +// Computes a smooth-edged diamond pixel value (Manhattan distance) +#define P(i, j, b) \ + vec2(.1, b).xyxy * smoothstep(0., 9. / R.y, .1 - abs(i) - abs(j)) + +// Computes a segment value (length = 0.5) +#define S(i, j, b) \ + P(i - clamp(i, 0., .5), j, b & 1) + +// Colon render +#define C \ + x += .5; O += P(x, y + .3, i.w / 50) + P(x, y - .3, i.w / 50); t /= 60 + +// Hyphen render +#define H(b) \ + ++x; O += S(x, y, b) + +// Computes the horizontal and vertical segments based on a denary digit +#define X(i, j, b) \ + S(x - i, y - j, b) +#define Y(i, j, b) \ + S(y - j, x - i, b) +#define D(n) \ + H(892>>n) \ + + X(0., .7, 1005>>n) \ + + X(0., -.7, 877>>n) \ + + Y(-.1, .1, 881>>n) \ + + Y(.6, .1, 927>>n) \ + + Y(-.1, -.6, 325>>n) \ + + Y(.6, -.6, 1019>>n); + +// Two-digit render +#define Z(n) ; D(n % 10) D(n / 10) + +void mainImage(out vec4 O, vec2 U) +{ + vec2 R = iResolution.xy; + U += U - R; + U /= R.y / 3.; // Global scaling with aspect ratio correction + O-=O; // Zero the pixel + + float x = U.x - U.y * .2 - 2.8, // Slight skew to slant the digits + y = --U.y; + ivec4 i = ivec4(iDate); // Convert everything to integers + int t = i.w; + i.w = int(iDate.w * 100.) % 100 // Replace with centiseconds + + // Seconds (preceded by a colon) + Z(t % 60) + C + + // Minutes (preceded by a colon) + Z(t % 60) + C + + // Hours + Z(t) + + // Smaller digits + x /= .6; + y /= .6; + R *= .6; + + // Centiseconds + x -= 14.; + y += .53 + Z(i.w) + + // Day (preceded by a hyphen) + x -= .8; + y += 3. + Z(i.z) + H(1) + + // Month (preceded by a hyphen) + Z((i.y + 1)) // Is it a bug in shadertoy that we have to add one? + H(1) + + // Year + Z(i.x % 100) + Z(i.x / 100) +} + +""" # noqa +shader = Shadertoy(shader_code) + +if __name__ == "__main__": + shader.show() From 9336b7bd682514856dd1628c0ccd04aad1b5d684 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 21 Nov 2023 22:21:59 +0100 Subject: [PATCH 7/7] Replace tabs with spaces --- examples/shadertoy_glsl_clock.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/shadertoy_glsl_clock.py b/examples/shadertoy_glsl_clock.py index 09597ad2..8ebb5c2d 100644 --- a/examples/shadertoy_glsl_clock.py +++ b/examples/shadertoy_glsl_clock.py @@ -7,11 +7,11 @@ // Computes a smooth-edged diamond pixel value (Manhattan distance) #define P(i, j, b) \ - vec2(.1, b).xyxy * smoothstep(0., 9. / R.y, .1 - abs(i) - abs(j)) + vec2(.1, b).xyxy * smoothstep(0., 9. / R.y, .1 - abs(i) - abs(j)) // Computes a segment value (length = 0.5) #define S(i, j, b) \ - P(i - clamp(i, 0., .5), j, b & 1) + P(i - clamp(i, 0., .5), j, b & 1) // Colon render #define C \ @@ -19,13 +19,13 @@ // Hyphen render #define H(b) \ - ++x; O += S(x, y, b) + ++x; O += S(x, y, b) // Computes the horizontal and vertical segments based on a denary digit #define X(i, j, b) \ - S(x - i, y - j, b) + S(x - i, y - j, b) #define Y(i, j, b) \ - S(y - j, x - i, b) + S(y - j, x - i, b) #define D(n) \ H(892>>n) \ + X(0., .7, 1005>>n) \ @@ -82,7 +82,7 @@ Z((i.y + 1)) // Is it a bug in shadertoy that we have to add one? H(1) - // Year + // Year Z(i.x % 100) Z(i.x / 100) }