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 
 31 import hat.ComputeContext.Kernel;
 32 import hat.KernelContext;
 33 import hat.NDRange;
 34 import hat.backend.Backend;
 35 import hat.buffer.F32Array;
 36 import hat.types.F32;
 37 import hat.types.mat2;
 38 import hat.types.vec2;
 39 import hat.types.vec3;
 40 import hat.types.vec4;
 41 import jdk.incubator.code.Reflect;
 42 import optkl.ifacemapper.MappableIface;
 43 import hat.buffer.Uniforms;
 44 import shade.ShaderViewer;
 45 import java.lang.invoke.MethodHandles;
 46 
 47 import static hat.types.F32.PIx2;
 48 import static hat.types.F32.abs;
 49 import static hat.types.F32.cos;
 50 import static hat.types.F32.fract;
 51 import static hat.types.F32.log;
 52 import static hat.types.F32.max;
 53 import static hat.types.F32.min;
 54 import static hat.types.F32.sin;
 55 import static hat.types.F32.smoothstep;
 56 import static hat.types.mat2.mat2;
 57 import static hat.types.vec2.abs;
 58 import static hat.types.vec2.add;
 59 import static hat.types.vec2.div;
 60 import static hat.types.vec2.dot;
 61 import static hat.types.vec2.floor;
 62 import static hat.types.vec2.fract;
 63 import static hat.types.vec2.length;
 64 import static hat.types.vec2.mul;
 65 import static hat.types.vec2.sub;
 66 import static hat.types.vec2.vec2;
 67 import static hat.types.vec3.add;
 68 import static hat.types.vec3.cos;
 69 import static hat.types.vec3.mix;
 70 import static hat.types.vec3.mul;
 71 import static hat.types.vec3.pow;
 72 import static hat.types.vec3.vec3;
 73 import static hat.types.vec4.normalize;
 74 import static hat.types.vec4.vec4;
 75 
 76 public class TruchetShader  {
 77 
 78   @Reflect public static mat2 rot(float a) {
 79         //  mat2 rot(float a) {return mat2(cos(a),sin(a),-sin(a),cos(a));}
 80         return mat2(cos(a), sin(a), -sin(a), cos(a));
 81     }
 82 
 83     @Reflect public static vec3 hue(float t, float f) {
 84         //  return f+f*cos(PI2*t*(vec3(1,.75,.75)+vec3(.96,.57,.12)));
 85         return add(f, mul(f, cos(mul(PIx2 * t,
 86                 add(vec3(1f, .75f, .75f), vec3(.96f, .57f, .12f))
 87         ))));
 88     }
 89 
 90     @Reflect public static float hash21(vec2 a) {
 91         // return fract(sin(dot(a,vec2(27.69,32.58)))*43758.53);
 92         return fract(sin(dot(a, vec2(27.69f, 32.58f))) * 43758.53f);
 93     }
 94 
 95     @Reflect public static  float box(vec2 p, vec2 b) {
 96         //vec2 d = abs(p)-b;
 97         vec2 d = sub(abs(p), b);
 98         // return length(max(d,0.)) + min(max(d.x,d.y),0.);}
 99         return length(vec2.max(d, 0f)) + min(max(d.x(), d.y()), 0f);
100     }
101 
102     @Reflect public static vec2 pattern(vec2 p, float sc) {
103         mat2 r90 = rot(1.5707f);
104         // vec2 uv = p;
105 
106         //vec2 id = floor(p*sc);
107         vec2 id = floor(mul(p, sc));
108         //p = fract(p*sc)-.5;
109         p = sub(fract(mul(p, sc)), .5f);
110 
111         float rnd = hash21(id);
112 
113         // turn tiles
114         if (rnd > .5f) {
115             p = mul(p, r90);
116         }
117         rnd = fract(rnd * 32.54f);
118         if (rnd > .4f) {
119             p = mul(p, r90);
120         }
121         if (rnd > .8f) {
122             p = mul(p, r90);
123         }
124 
125         // randomize hash for type
126         rnd = fract(rnd * 47.13f);
127 
128         float tk = .075f;
129         // kind of messy and long winded
130         float d = box(sub(p, vec2(.6f, .7f)), vec2(.25f, .75f)) - .15f;
131         float l = box(sub(p, vec2(.7f, .5f)), vec2(.75f, .15f)) - .15f;
132         float b = box(add(p, vec2(0f, .7f)), vec2(.05f, .25f)) - .15f;
133         float r = box(add(p, vec2(.6f, 0f)), vec2(.15f, .05f)) - .15f;
134         d = abs(d) - tk;
135 
136         if (rnd > .92f) {
137             d = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
138             l = box(sub(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
139             b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
140             r = box(sub(p, vec2(.6f, -.6f)), vec2(.25f)) - .15f;
141             d = abs(d) - tk;
142 
143         } else if (rnd > .6f) {
144             d = F32.abs(p.x() - .2f) - tk;//length(p.x()-.2f)-tk;
145             l = box(sub(p, vec2(-.6f, .5f)), vec2(.25f, .15f)) - .15f;
146             b = box(add(p, vec2(.6f, .6f)), vec2(.25f)) - .15f;
147             r = box(sub(p, vec2(.3f, 0f)), vec2(.25f, .05f)) - .15f;
148         }
149 
150         l = abs(l) - tk;
151         b = abs(b) - tk;
152         r = abs(r) - tk;
153 
154         float e = min(d, min(l, min(b, r)));
155 
156         if (rnd > .6f) {
157             r = max(r, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
158             d = max(d, -box(add(p, vec2(-.2f, .2f)), vec2(tk * 1.3f)));
159         } else {
160             l = max(l, -box(sub(p, vec2(.2f, .2f)), vec2(tk * 1.3f)));
161         }
162 
163         d = min(d, min(l, min(b, r)));
164 
165         return vec2(d, e);
166     }
167 
168     @Reflect public static vec4 createPixel(vec2 fres, float ftime, vec2 fmouse, vec2 fragCoord){
169 
170 
171         vec3 color = vec3(0f);
172         // vec2 uv = (2.*F-R.xy)/max(R.x,R.y);
173         var uv = div(sub(mul(2f,fragCoord),fres),max(fres.x(),fres.y()));
174 
175         // uv *= rot(T*.095);
176         //   uv = mul(uv, rot(fTime * .095f));
177 
178         // uv = vec2(log(length(uv)), atan(uv.y, uv.x)*6./PI2);
179         // Original.
180         //uv = vec2(log(length(uv)), atan(uv.y, uv.x))*8./6.2831853;
181 
182         uv = vec2(log(length(uv)), F32.atan(uv.y(), uv.x()) * 6f / (PIx2));
183 
184         float scale = 8f;
185         for (float i = 0f; i < 4f; i++) {
186             float ff = (i * .05f) + .2f;
187             // uv.x+=T*ff;
188             uv = add(uv, vec2(ftime * ff, 0f));
189 
190             float fwidth = 0.0001f;
191             float px = fwidth;//fwidth(uv.x*scale);
192             // vec2 d = pattern(uv,scale);
193             vec2 d = pattern(uv, scale);
194             // vec3 clr = hue(sin(uv.x+(i*8.))*.2+.4,(.5+i)*.15);
195             vec3 clr = hue(sin(uv.x() + (i * 8f)) * .2f + .4f, (.5f + i) * .15f);
196             // C = mix(C,vec3(.001),smoothstep(px,-px,d.y-.04));
197             color = mix(color, vec3(.001f), smoothstep(px, -px, d.y() - .04f));
198             // C = mix(C,clr,smoothstep(px,-px,d.x));
199             color = mix(color, clr, smoothstep(px, -px, d.x()));
200             scale *= .5f;
201         }
202 
203         // Output to screen
204         color = pow(color, vec3(.4545f));
205         return normalize(vec4(color, 1.0f));
206     }
207 
208     @Reflect public static vec4 mainImage(Uniforms uniforms, vec4 fragColor, vec2 fragCoord) {
209         return createPixel(vec2(uniforms.iResolution().x(),uniforms.iResolution().y()),uniforms.iTime(),vec2(uniforms.iMouse().x(),uniforms.iMouse().y()),fragCoord);
210     }
211     @Reflect
212     public static void penumbra(@MappableIface.RO KernelContext kc, @MappableIface.RO Uniforms uniforms, @MappableIface.RW F32Array f32Array) {
213         int width = (int) uniforms.iResolution().x();
214         int height = (int) uniforms.iResolution().y();
215         var fragColor = mainImage(uniforms, vec4.vec4(0f), vec2.vec2((float)(kc.gix % width), (float)(height-(kc.gix / width))));
216         f32Array.array(kc.gix * 3, fragColor.x());
217         f32Array.array(kc.gix * 3+1, fragColor.y());
218         f32Array.array(kc.gix * 3+2, fragColor.z());
219     }
220 
221     @Reflect
222     static public void compute(final ComputeContext computeContext, @MappableIface.RO Uniforms uniforms, @MappableIface.RO F32Array image, int width, int height) {
223         computeContext.dispatchKernel(NDRange.of1D(width * height), (@Reflect Kernel) kc -> penumbra(kc, uniforms, image));
224     }
225 
226     private static void update(  Accelerator acc, Uniforms uniforms, F32Array f32Array, int width, int height) {
227         acc.compute((@Reflect Compute) cc -> compute(cc, uniforms, f32Array, width, height));
228     }
229 
230     static void main(String[] args) {
231         var acc = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
232         var shader = ShaderViewer.of(acc, TruchetShader.class,1024, 1024);
233         shader.startLoop((uniforms, f32Array) -> update( acc, uniforms, f32Array, shader.view.getWidth(), shader.view.getHeight()));
234     }
235 }
236