1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package shade.shaders;
 26 
 27 import hat.Accelerator;
 28 import hat.Accelerator.Compute;
 29 import hat.ComputeContext;
 30 import hat.ComputeContext.Kernel;
 31 import hat.KernelContext;
 32 import hat.NDRange;
 33 import hat.backend.Backend;
 34 import hat.buffer.F32Array;
 35 import hat.types.F32;
 36 import hat.types.vec2;
 37 import hat.types.vec4;
 38 import jdk.incubator.code.Reflect;
 39 import optkl.ifacemapper.MappableIface;
 40 import hat.buffer.Uniforms;
 41 import shade.ShaderViewer;
 42 import java.lang.invoke.MethodHandles;
 43 
 44 import static hat.types.F32.abs;
 45 import static hat.types.F32.floor;
 46 import static hat.types.F32.log;
 47 import static hat.types.F32.max;
 48 import static hat.types.F32.mod;
 49 import static hat.types.mat2.mat2;
 50 import static hat.types.vec2.abs;
 51 import static hat.types.vec2.add;
 52 import static hat.types.vec2.div;
 53 import static hat.types.vec2.dot;
 54 import static hat.types.vec2.floor;
 55 import static hat.types.vec2.fract;
 56 import static hat.types.vec2.length;
 57 import static hat.types.vec2.mul;
 58 import static hat.types.vec2.sub;
 59 import static hat.types.vec2.vec2;
 60 import static hat.types.vec4.add;
 61 import static hat.types.vec4.cos;
 62 import static hat.types.vec4.div;
 63 import static hat.types.vec4.mul;
 64 import static hat.types.vec4.normalize;
 65 import static hat.types.vec4.smoothstep;
 66 import static hat.types.vec4.vec4;
 67 
 68 
 69 //https://shadertoy.com/view/3llcDl
 70 public class SpiralShader{
 71 
 72     /*
 73     // variant of https://shadertoy.com/view/3llcDl
 74     // inspired by https://www.facebook.com/eric.wenger.547/videos/2727028317526304/
 75 
 76     void mainImage(out vec4 fragColor,  vec2 fragCoord ){
 77 
 78         vec2 fResolution = iResolution.xy;
 79 
 80         vec2  U = ((2.*fragCoord - fResolution)) / fResolution.y; // normalized coordinates
 81         vec2  z = U - vec2(-1,0);
 82         U.x = U.x-.5;                      // Moebius transform
 83 
 84         U = U * mat2(z,-z.y,z.x) / dot(U,U);
 85 
 86         U = U+.5;
 87                       // offset   spiral, zoom   phase            // spiraling
 88         U =   log(length(U))*vec2(.5, -.5) + iTime/8. + atan(U.y, U.x)/6.2832 * vec2(6, 1);
 89         // n
 90         U = U * 3./vec2(2,1);
 91         z = //vec2(1);
 92         fwidth(U);
 93         U = fract(U)*5.;
 94 
 95         vec2 I = floor(U);
 96         U = fract(U);              // subdiv big square in 5x5
 97         I.x = mod( I.x - 2.*I.y , 5.);                            // rearrange
 98         U = vec2(U.x+ float(I.x==1.||I.x==3.),U.y+float(I.x<2.));     // recombine big tiles
 99 
100         float id = -1.;
101 
102         if (I.x != 4.){
103             U =U/2.;                                     // but small times
104             id = mod(floor(I.x/2.)+I.y,5.);
105         }
106         U = abs(fract(U)*2.-1.);
107          float v = max(U.x,U.y);          // dist to border
108         fragColor =   smoothstep(.7,-.7, (v-.95)/( abs(z.x-z.y)>1.?.1:z.y*8.))  // draw AA tiles
109             * (id<0.?vec4(1): .6 + .6 * cos( id  + vec4(0,23,21,0)  ) );// color
110     }
111      */
112 
113 
114     @Reflect
115     public static vec4 createPixel(vec2 fres, float ftime, vec2 fmouse, vec2 fragCoord){
116 
117             // variant of https://shadertoy.com/view/3llcDl
118 // inspired by https://www.facebook.com/eric.wenger.547/videos/2727028317526304/
119 
120 
121             vec2 U = div(sub(mul(fragCoord, 2f), fres), fres.y());//.sub(fResolution).div(fResolution.y());
122             // normalized coordinates
123             var z = sub(U, vec2(-1f, 0f));
124 
125             U = sub(U, vec2(.5f, 0f));
126             U = div(
127                     mul(U, mat2(z.x(), z.y(), -z.y(), z.x())),
128                     dot(U, U)
129             );
130             // offset   spiral, zoom   phase            // spiraling
131             U = add(U, .5f);
132             //U =   log(length(U))*vec2(.5, -.5) + iTime/8. + atan(U.y, U.x)/6.2832 * vec2(6, 1);
133             U = add(
134                     add(
135                             mul(log(length(U)), vec2(.5f, 0.5f)),
136                             vec2(ftime / 8f)
137                     ),
138                     mul(
139                             F32.atan(U.x(), U.y())/ 6.2832f,
140                             vec2(6f, 1f)
141                     )
142             );
143 
144 
145             U = div(mul(U, vec2(3f)), vec2(2f, 1f));
146             z = vec2(.001f);//fwidth(U); // this resamples the image.  Not sure how we do this!
147             U = mul(fract(U), 5f);
148             vec2 I = floor(U);
149             U = fract(U);             // subdiv big square in 5x5
150             I = vec2(mod(I.x() - 2.f * I.y(), 5f), I.y());                            // rearrange
151           //  U =  vec2((I.x() == 1f || I.x() == 3f) ? 1f : 0f, I.x() < 2.0 ? 1f : 0f);     // recombine big tiles
152         U = add(U, vec2((I.x() == 1f || I.x() == 3f) ? 1f : 0f, I.x() < 2.0 ? 1f : 0f));     // recombine big tiles
153         float id = -1f;
154             if (I.x() != 4f) {
155                 U = div(U, 2f);                                     // but small times
156                 id = mod(floor(I.x() / 2f) + I.y(), 5f);
157             }
158             U = sub(abs(mul(fract(U), 2f)), 1f);
159             float v = max(U.x(), U.y());          // dist to border
160 
161             return
162                     //normalize(
163                             smoothstep(
164                                     vec4(.7f),
165                                     vec4(-.7f),
166                                     mul(div(vec4(v - .95f), abs(z.x() - z.y()) > 1f
167                                                     ? .1f
168                                                     : z.y() * 8f
169                                             )
170                                             , id < 0f
171                                                     ? vec4(1f)
172                                                     : add(mul(vec4(.6f), .6f),
173                                                     cos(add(vec4(id), vec4(0f, 23f, 21f, 0f)))
174                                             )
175                                     )
176                          //   )
177                     );// color
178         }
179     @Reflect public static vec4 mainImage(Uniforms uniforms, vec4 fragColor, vec2 fragCoord){
180         return createPixel(vec2(uniforms.iResolution().x(),uniforms.iResolution().y()),uniforms.iTime(),vec2(uniforms.iMouse().x(),uniforms.iMouse().y()),fragCoord);
181     }
182 
183     @Reflect
184     public static void penumbra(@MappableIface.RO KernelContext kc, @MappableIface.RO Uniforms uniforms, @MappableIface.RW F32Array f32Array) {
185         int width = (int) uniforms.iResolution().x();
186         int height = (int) uniforms.iResolution().y();
187         var fragColor = mainImage(uniforms, vec4.vec4(0f), vec2.vec2((float)(kc.gix % width), (float)(height-(kc.gix / width))));
188         f32Array.array(kc.gix * 3, fragColor.x());
189         f32Array.array(kc.gix * 3+1, fragColor.y());
190         f32Array.array(kc.gix * 3+2, fragColor.z());
191     }
192 
193     @Reflect
194     static public void compute(final ComputeContext computeContext, @MappableIface.RO Uniforms uniforms, @MappableIface.RO F32Array image, int width, int height) {
195         computeContext.dispatchKernel(NDRange.of1D(width * height), (@Reflect Kernel) kc -> penumbra(kc, uniforms, image));
196     }
197 
198     public static void update(  Accelerator acc, Uniforms uniforms, F32Array f32Array, int width, int height) {
199         acc.compute((@Reflect Compute) cc -> compute(cc, uniforms, f32Array, width, height));
200     }
201 
202     static void main(String[] args) {
203         var acc = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
204         var shader = ShaderViewer.of(acc, SpiralShader.class,1024, 1024);
205         shader.startLoop((uniforms, f32Array) -> update( acc, uniforms, f32Array, shader.view.getWidth(), shader.view.getHeight()));
206     }
207 }