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